Click here to Skip to main content
Click here to Skip to main content

Thunder Measurement Unit Conversion Framework

By , 23 Dec 2005
Rate this:
Please Sign up or sign in to vote.

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);
    
    //"result" now holds 5kg as grams

    ...
    
    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");
    
    //5 Kilogram input (space between value and units optional)
    string initial = "5 kg";
    //Convert to grams in this example
    string target_unit = "g";
    
    //Some placeholder variables
    string initial_units = "":
    double initial_val = 0.0;
    double result = 0.0;
    
    //Break up the input string
    uc.ParseUnitString(initial, out initial_val, out initial_units);

    //Perform conversion
    uc.ConvertUnits(initial_val, initial_units, 
                      target_unit, out result);
    
    //Print out the 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");

//Give the data strings some value
d1.SetValue("2 kg");
d2.SetValue("500 g");    //0.5kg

DataString d3 = d1 + d2;

Console.WriteLine(d3.ToString( ));
//Should be 2.5kg in this example.
...

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

  • v1.00 - Initial version.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Rob Harwood
Web Developer
United Kingdom United Kingdom
Born in England, I have been programming since a very early age when my dad gave me prewritten programs to type in and run on a Sinclair ZX81 machine (seeing my name printed out on a TV screen was enough to keep me entertained!). I later did work using basic and STOS basic on the Atari ST and after that got my first PC and used Microsoft's QBasic. Later when I was about 13 I was in an airport and saw a trial copy of Visual Basic on a magazine, which I bought and it got me hooked on the Microsoft development tools.
 
Currently I am studying a software engineering degree and have been working with .NET since 1.0. I have just moved over to Visual Studio 2005/.NET 2.0 and am loving it! During my degree I have worked for a year at DuPont, where I ended up changing a lot of their old existing software over to .NET and improving it in the process! Since then I have been back and done some consulting work involving maintaining some of their older C++/MFC software.
 
While most of my current interestes involve .NET I am also confident in working with C++ in Win32, VB, Java, and have even done some development work on the Linux platform (although most of this involved ensuring that software I wrote in C++ was platform independent).
 
I have a strong passion for software technology, both higher level and more recently, systems level stuff (the dissertation I am doing for my degree is to implement a small compiler and virtual machine in C# for a Pascal-style language).

Comments and Discussions

 
Generalhttp://www.unidata.ucar.edu/software/udunits/udunits-2/udunits2.html Pinmemberdanong29-Jan-09 11:02 
GeneralRe: http://www.unidata.ucar.edu/software/udunits/udunits-2/udunits2.html Pinmember5unkR28-Sep-09 21:10 
GeneralCulture issue PinmemberNicolas Mohamed24-Dec-07 2:59 
GeneralFlexible but Underdocumented PinmemberMark Treadwell15-Apr-07 3:37 
GeneralError PinmemberMark Treadwell15-Apr-07 7:45 
GeneralTemperature conversion is not correct! PinmemberJAY.ca5-May-06 22:13 
GeneralRe: Temperature conversion is not correct! Pinmemberguyinfun6-Feb-07 10:39 
GeneralRe: Temperature conversion is not correct! Pinmembergclinkscode29-Mar-07 9:19 
AnswerRe: Temperature conversion is not correct! Pinmemberhanan.ta2-Oct-09 6:07 
Generalbad conversion Pinmemberjwaltman3-Mar-06 10:06 
GeneralLicense Pinmemberfkohan24-Jan-06 5:42 
GeneralRe: License PinmemberRob Harwood24-Jan-06 5:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140415.2 | Last Updated 23 Dec 2005
Article Copyright 2005 by Rob Harwood
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid