
Introduction
The Thunder library provides extensible measurement unit conversion functionality, allowing a program that may need to work with multiple units and perform unit conversion to do so with ease. This article introduces Thunder, describes the functionality and how to use the library, and provides a sample program that uses the library to perform a variety of unit conversions. Also provided is a configuration file containing lots of pre-made common units.
Theory of Unit Conversion in Thunder
Any unit can be converted into another as long as they measure the same thing. From simple conversions (like millimeters to meters) to more complex ones (such as Kelvin to Fahrenheit), every conversion consists of basic mathematical formulae which usually involve some simple multiplication, addition, or division.
Thunder works on the principle that every unit belongs to a category (i.e. Temperature, Mass, Energy etc.) and every category has a standard unit (e.g. Kelvin for temperature). The standard unit gives Thunder a point of reference for the unit category. Every other unit listed in the unit configuration file contains the mathematical data to convert it into the standard. All the Thunder library does is simply convert the original unit into the standard, then convert the standard value into the output unit.
The unit definitions are represented as XML in the Thunder configuration file. Below is a sample of the provided units file:
<Unit name="Kelvin">
<Symbol default="true">K</Symbol>
<Multiply>1</Multiply>
</Unit>
<Unit name="Celcius">
<Symbol default="true">C</Symbol>
<Add>273.15</Add>
</Unit>
Each unit resides within a "Unit
" tag, the full name of the unit is in the property of the tag, and the data for the unit is inside the tag. Each unit can have multiple symbols associated with it (a symbol meaning a shorthand affix for the unit, such as "cm" for centimeters) and one of the symbols can be promoted to the default.
See the provided "units.xml" for full comments and examples.
Using the Code
There is just one main class that is needed to provide the conversion, and this is available via the IUnitConverter
interface. This provides a single point of entry into all of the conversion functionality, and contains some methods:
LoadUnitsFile
- Given a path to a unit configuration file, will load the units within the file into the converter.
InitTables
- Unloads all the loaded units and returns the converter to a blank state.
GetUnitByName
- Gets an object representing a unit by giving the name of the unit (e.g. "Kelvin").
GetUnitBySymbol
- Same as GetUnitByName
, only takes a unit symbol as a reference (e.g. "mm" or "km" etc.).
CompatibleUnits
- Returns a boolean to determine if two units are compatible. For example, "mm" and "km" are compatible, however "mm" and "kg" are not.
ConvertUnits
- The heart of the functionality, takes the current value, current unit, and the target unit. Returns an error code and outputs the converted value in an out
parameter.
ParseUnitString
- Given a string of value and unit, separates out the value and unit (example input: "5 kg").
CreateDataString
- Creates a "data string" (more on data strings later).
public static void main( )
{
IUnitConverter uc = Thor.Units.InterfaceFactory.CreateUnitConverter( );
uc.LoadUnitsFile(@".\units.xml");
double result;
uc.ConvertUnits(5.0, "kg", "g", out result);
...
return 0;
}
The code above shows instantiating the unit converter, and converting 5 kilograms to grams. However, programs will tend to work with textboxes or strings containing unit/value combinations such as "5 kg". Handling this is shown in the code below:
public static void main( )
{
IUnitConverter uc =
Thor.Units.InterfaceFactory.CreateUnitConverter( );
uc.LoadUnitsFile(@".\units.xml");
string initial = "5 kg";
string target_unit = "g";
string initial_units = "":
double initial_val = 0.0;
double result = 0.0;
uc.ParseUnitString(initial, out initial_val, out initial_units);
uc.ConvertUnits(initial_val, initial_units,
target_unit, out result);
Console.WriteLine("{0} = {1}{2}", initial, result, target_unit);
return 0;
}
You can also look at the demo project, "Thor.TestApp", which allows a user to input any initial value and target unit, and see the conversion in real time.
The DataString class
The DataString
class is an object that represents a value and a unit. It can be used as part of the backend of a user interface to provide validation services or access to the conversion system in a different way.
Take the following code:
...
uc = Thor.Units.InterfaceFactory.CreateUnitConverter( );
uc.OnError += new UnitEventHandler(uc_OnError);
uc.LoadUnitsFile(@".\units.xml");
DataString d1 = uc.CreateDataString("kg");
DataString d2 = uc.CreateDataString("kg");
d1.SetValue("2 kg");
d2.SetValue("500 g");
DataString d3 = d1 + d2;
Console.WriteLine(d3.ToString( ));
...
This shows the unit converter being instantiated, then two data strings created with an initial unit - this is important as it sets the unit group that the data strings belong to (in this case, weight). The value of the two data strings is then set (notice, the string given is a complete value/unit pair - this changes the unit of the data string). The data strings are then added together, notice that they are being added but are actually in different units ("kg" vs. "g"), the converter automatically handles this and the output is "2.5kg". This would work great for programs that need to manipulate unitized data but want to allow a user to enter the data in units they are familiar with. The hard coded values in this example could easily be the contents of a textbox or something.
Points of Interest
You can add values in any units you like! Editing the XML file is easy and feel free to post if you get stuck.
Study the code - notice that the data string also supports max/min bounds and unit locking (so it always gives text output as one kind of unit). See the DataStringFlags
enum for more information.
In the \Bin directory of the source ZIP is the example units.xml configuration file and the precompiled binaries.
History