UNITS OF MEASUREMENT
FOR ADA
version 2.0
by Dmitry A. Kazakov
(mailbox@dmitry-kazakov.de)
This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate generics from this unit, or you link this unit with other files to produce an executable, this unit does not by itself cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU Public License.
The need of support for handling measurement units does not require any approval. It is in particular true for the Ada programming language with its stress on safety and maintainability. The proposed set of packages represents a possible solution of the unit problem. Dimension checking is performed at run-time, so performance is sacrificed for safety. However, an attempt was made to reduce performance hit. The type Measure used to represent dimensioned values can be constrained to a specific unit. Operations on constrained subtypes of Measure could be potentially as efficient as floating-point operations. They are declared inlined, so that at least theoretically, a decent compiler could perform discriminant calculation and check at compile time.
The key features of the approach:
Download
units_2_0.tgz (tar + gzip, Windows users may use WinZip)
You may wish to visit this site devoted to the problem of dimensioned values in Ada.
The units converter is a small dialog box where you can enter a dimensioned value and then convert it to SI:
Ready-to-use executables:
Windows x86 |
![]() |
Linux_GTK i686 statically linked |
![]() |
The source code is discussed in the section 3.2.
Two types are used for dealing with units. The type Unit denotes the dimension of a physical entity. The type Measure represents a dimensioned value it is defined in a generic package Measures which is instantiated with the desired floating-point type as the parameter:
generic
type Number is digits <>;
package Measures is
...
The package Float_Measures is an instance of Measures for the standard Float type: .
The type Unit is defined in the package Units. A value of the type Unit corresponds to a kind of physical entity, like energy, charge or velocity. The package itself is rather useless, because there are few things one can do with units. They are:
Or in terms of Ada the following functions are defined:
function "**" (Left : Unit; Right : Integer) return Unit;
function "*" (Left, Right : Unit) return Unit;
function "/" (Left, Right : Unit) return Unit;
function Sqrt (X : Unit) return Unit;
Values of the type Unit build a group. A value of Unit type can be viewed as an unordered set of seven base components (mass, length, time, current etc.). Each component has integer exponent part. The function Sqrt is defined for only units which components have even exponent parts. The exception Constraint_Error is propagated when the result of an operation is illegal.
The package also declares the exception Unit_Error and the type:
The child package Units.Base defines the base units:
Current : constant Unit;
Luminescence : constant Unit;
Temperature : constant Unit;
Mass : constant Unit;
Length : constant Unit;
Quantity : constant Unit;
Time : constant Unit;
Unitless : constant Unit;
The child package Units.Constants defines some of more complex units. Geometric
units are:
Area : constant Unit := Length ** 2;
Volume : constant Unit := Length ** 3;
Units used in mechanics:
Velocity : constant Unit := Length / Time;
Acceleration : constant Unit := Length / Time ** 2;
Force : constant Unit := Mass * Acceleration;
Pressure : constant Unit := Force / Area;
Energy : constant Unit := Force * Length;
Power : constant Unit := Energy / Time;
Electricity units:
Charge : constant Unit := Current * Time;
Potential : constant Unit := Energy / Charge;
Capacitance : constant Unit := Charge / Potential;
Resistance : constant Unit := Potential / Current;
Conductance : constant Unit := Current / Potential;
Inductance : constant Unit := Potential * Time / Current;
Chemistry units:
Concentration : constant Unit := Quantity / Volume;
Density : constant Unit := Mass / Volume;
Optic units:
Luminance : constant Unit := Luminescence / Area;
Other units:
Frequency : constant Unit := Unitless / Time;
The package Units.Edit provides the function Image is used to convert Unit to String:
function Image
( Value : Unit;
Latin1 : Boolean := True
) return String;
The syntax of the result string is:
<result> ::= <list>/<list> | 1/<list> | <list> | 1 <list> ::= <item> [<*><list>] <item> ::= <base-unit>[<power>] <base-unit> ::= A | cd | K | kg | m | mol | s
Here <*> is either * (if Latin1 is false), or · from Latin-1 character set. When Latin1 is false <power> is always ^<number>. With Latin-1 character set enabled, powers 2 and 3 are indicated using the corresponding superscript characters: 2 and 3. The following table lists the Latin-1 characters used for output:
Character | Latin-1 | Meaning |
2 | B216 | Power 2 |
3 | B316 | Power 3 |
· | B716 | Multiplication operator |
The package Units.UTF8_Edit provides the function Image used to convert Unit to an UTF-8 encoded string:
function Image (Value : Unit) return String;
The syntax of the result string is:
<result> ::= <list>/<list> | <list> | 1 <list> ::= <item> [·<list>] <item> ::= <base-unit>[<power>] <base-unit> ::= A | cd | K | kg | m | mol | s <power> ::= [-]<number> <number> ::= <digit>[<number>] <digit> ::= 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
Powers are output as superscript digits. When all powers are negative, the output uses no fraction but negative powers instead. For example: m-2 instead of 1/m2. The following table summarizes the list of special characters and their encodings in UTF-8:
Character | UTF-8 encoding | Code point | Meaning |
2 | C216 B216 | 00B216 | Power 2 |
3 | C216 B316 | 00B316 | Power 3 |
4 | E216 8116 B416 | 207416 | Power 4 |
5 | E216 8116 B516 | 207516 | Power 5 |
6 | E216 8116 B616 | 207616 | Power 6 |
7 | E216 8116 B716 | 207716 | Power 7 |
8 | E216 8116 B816 | 207816 | Power 8 |
9 | E216 8116 B916 | 207916 | Power 9 |
- | E216 8116 BB16 | 207B16 | Power - |
· | C216 B716 | 00B716 | Multiplication operator |
Some words about the design. I didn't make the type Unit private because then it could not be used as a discriminant of the type Measure (see the package Measures). To have Measure discriminated seems to be very important. It allows to define subtypes of Measure with fixed Unit component. For the same reason and for performance sake too, Unit is a modular number. As the result it inherits a number of operations which are disallowed by making them abstract. In the current implementation the type Interfaces.Unsigned_32 is used. This determines the range of the exponent part of a base component as -8..7. With Interfaces.Unsigned_64 the range would be -512..511. The following fragment of the file units.ads can be modified if the compiler supports modular numbers larger than Interfaces.Unsigned_32:
with
Interfaces; package Units is -- -- Here we define the type used to represent units. It should be a -- modular type with a defined operation Shift_Right. -- subtype UnitPower is Interfaces.Unsigned_; . . . |
Rational powers are not allowed, because the choice of base units in SI ensures whole powers of all physical values. Examples like Schottky-Langmuir equation can be easily written in a correct form with whole powers. Often it is argued that rational powers might be useful for dealing with intermediate results. A simple example x = ln ex shows that in general case it cannot be done anyway.
A value of the type Measure (defined in the package Measures) represents some quantity of a physical unit:
type Measure (SI : Unit := Units.Base.Unitless) is record
Gain : Number;
Offset : Number'Base := 0.0;
end record;
Measures can be added, subtracted, multiplied, divided and exponentiated.
The type Measure is a discriminated record type.
The discriminant SI has the type Unit. Its value defines
the dimension of a Measure. Unconstrained instances
of Measure can be declared as:
Entity : Measure; -- May hold value of any measurement unit
. . .
Entity := 5.0 * A / s; -- Set value 5 A/s
Entity := 3.0 * km; -- Set value 3.0 km
Entity := Entity + s; -- Illegal (km + s), Unit_Error
It is possible however, to create constrained subtypes of
Measure capable to hold values of only a specific
dimension. For instance:
subtype Speed is Measure (Velocity);
Car_Speed : Speed; -- Only velocities are allowed
. . .
Car_Speed := 10.0 * km / h; -- OK
Car_Speed := A; -- Illegal, Constraint_Error
The type Measure has two components: Gain and Offset.
To get a SI equivalent of the value one should sum Gain and Offset. This
is what the function Get_Value actually does. For
instance:
Meter : Measure := (Length, Gain=>1.0, Offset=>0.0);
Foot : Measure := (Length, Gain=>0.3048, Offset=>0.0);
The subtype Dimensionless for dimensionless measures.
The field Offset of the type Measure defines the value
shift. Measures with zero Offset are called unshifted. They form a field
with addition and multiplication operations:
Meter : Measure := (Length, Gain=>1.0, Offset=>0.0);
Foot : Measure := (Length, Gain=>0.3048, Offset=>0.0);
. . .
Meter * Foot -- 0.3048 square meters
Meter + Foot -- 1.3048 m
Meter ** 2 -- 1 square meter
Most of physical units and all SI units are unshifted. Shifted measurement
units are rare. Degrees of Celsius and Fahrenheit is an example of shifted
units. The degree of Celsius can be defined as:
Celsius : Measure := (Temperature, Gain=>1.0, Offset=>273.15);
Actually, the field Offset should also be a discriminant of the type
Measure. Unfortunately it is illegal in Ada. Measures
of same dimension and shift form a set closed relatively addition, subtraction
and multiplication to a number (i.e. a group). Therefore:
5.0 * Celsius -- Legal, 5ºC = 278.15 K
Celsius + Celsius -- Legal, 2ºC = 275.15 K
Celsius * Celsius -- Illegal, Unit_Error is propagated
In other words, shifted measures can be neither multiplied nor divided, except
when a shifted measure is multiplied to or divided by a dimensionless unshifted
value as in the first example above. Note
that addition and subtraction are only legal when dimension and shift are
same for both operands:
Kelvin : Measure := (Temperature, Gain=>1.0, Offset=>0.0);
Celsius : Measure := (Temperature, Gain=>1.0, Offset=>273.15);
. . .
Celsius + Kelvin -- Illegal, Unit_Error is propagated
Celsius * Kelvin -- Illegal, Unit_Error is propagated
Mixing of differently shifted measures is ambiguous. In the given example
Celsius and Kelvin could be added if one would be converted to another:
Convert (Celsius, Kelvin) + Kelvin -- +275.15 K (unshifted) = 2ºC
Celsius + Convert (Kelvin, Celsius) -- -271.15ºC (shifted) = 2 K
Note that the numeric equivalent of the result depends on whether Celsius
is converted to Kelvin or inversely. Even if two zeros (0ºC and 0 K)
are added the results will differ:
Convert (0.0 * Celsius, Kelvin) + 0.0 * Kelvin -- +273.15 K (0ºC)
0.0 * Celsius + Convert (0.0 * Kelvin, Celsius) -- -273.15ºC (0 K)
Unary operations:
function "abs" (Right : Measure) return Measure;
function "+" (Right : Measure) return Measure;
function "-" (Right : Measure) return Measure;
Exponentiation:
function "**" (Left : Measure; Right : Integer) return Measure;
Multiplication:
function "*" (Left : Number'Base; Right : Measure) return Measure;
function "*" (Left : Measure; Right : Number'Base) return Measure;
function "*" (Left, Right : Measure) return Measure;
Division:
function "/" (Left : Number'Base; Right : Measure) return Measure;
function "/" (Left : Measure; Right : Number'Base) return Measure;
function "/" (Left, Right : Measure) return Measure;
Addition and subtraction:
function "+" (Left, Right : Measure) return Measure;
function "-" (Left, Right : Measure) return Measure;
Comparisons:
function ">" (Left, Right : Measure) return Boolean;
function "<" (Left, Right : Measure) return Boolean;
function "=" (Left, Right : Measure) return Boolean;
function ">=" (Left, Right : Measure) return Boolean;
function "<=" (Left, Right : Measure) return Boolean;
The equality operator can be applied to any pair of measures. The inequality operation is implicitly defined by the compiler.
Scale shift (value destructive):
function "and" (Left : Measure; Right : Number'Base) return Measure;
The result of scale shift is formed by adding the value of
the parameter Right to the field Offset. Note that the numeric SI
equivalent of the result will differ from one of the parameter Left.
For instance:
Celsius : constant Measure := K and 273.15; -- 1ºC (is not equal to 1 K)
See also the functions Normalize and Shift which perform scale shifts retaining the value.
The exception Constraint_Error is raised by the operations when the corresponding numeric operation does. This behavior depends on whether Number’Machine_Overflows is true, as Ada Reference Manual states in 4.5.5 (22). Also Constraint_Error is propagated out of multiplicative operations "*", "/" and "**" when the dimension of the result cannot be represented as Unit because of a base unit power overflow.
The function Get_Value returns a SI equivalent of the argument:
function Get_Value (Value : Measure) return Number;
The function Get_Value_As returns a numeric equivalent of the first argument
in the measurement units defined by the second argument:
function Get_Value_As (Value, Scale : Measure) return Number;
For instance Get_Value_As (T, Celsius) returns the value of T in degrees of
Celsius. The arguments Value and Scale should have same units.
Otherwise the exception Unit_Error is propagated.
function Normalize (Value : Measure) return Measure;
The function Normalize returns an unshifted measure
with the numeric equivalent same as one of the argument. For example:
Zero : Measure := Normalize (0.0 * Celsius); -- 273.15 K (unshifted)
Here 0ºC is converted to its unshifted equivalent 273.15 K.
function Shift (Value : Measure, Shift : Number'Base) return Measure;
The function Shift returns the argument shifted to
Shift items. Unlike the operation and, the numeric
equivalent of the result is same as one of the first argument. The value
of the parameter Shift is subtracted from the field Gain and added
to the field Offset to produce the result:
Zero : Measure := Shift (0.0 * Celsius, -273.15); -- 273.15 K
Here 0ºC is converted to its unshifted equivalent 273.15 K. Note that Normalize (X) is equivalent to Shift (X, X.Offset).
function Convert (Value, Scale : Measure) return Measure;
The function Convert is used for measurement unit conversions. The value of the first argument is converted to the measurement units of the second argument. The arguments Value and Scale should have same dimension. Otherwise the exception Unit_Error is propagated. Convert (X, Y) is an equivalent of Shift (X, Y.Offset - X.Offset). This is null operation if both arguments have same Offsets. Otherwise, the result has the shift of the second argument.
function To_Measure (Value : Number) return Measure;
This function returns a dimensionless unshifted measure corresponding to Value.
Few constants of the type Measure are defined in the
package Measures. They correspond to the base SI measurement units:
Constant | The base SI unit |
A | Ampere |
cd | Candela |
K | Kelvin |
kg | Kilogram |
m | Meter |
mol | Mole |
s | Second |
and dimensionless SI units:
Constant | Meaning |
Np | Neper* |
rad | Radian, plane angle |
sr | Steradian, solid angle |
* Neper is not a SI unit. It is put here to have a constant for 1 SI other than rad. Actually Np = rad = sr
The generic package Measures_Derived defines the constants corresponding to the derived SI measurement units:
generic
with package Measures is new Standard.Measures (<>);
package Measures_Derived is ...
The package defines the following constants:
Constant | Unit | Comment |
C | Coulomb | |
F | Farad | |
Gy | Gray | |
Henry | Henry | The full name Henry is used instead of H to reserve h for hour, which being a non-SI unit would be still more important for many than Henry |
Hz | Hertz | |
J | Joule | |
lm | Lumen | |
lx | Lux | |
N | Newton | |
Ohm | Ohm | The short name (Greek omega Ω) does not belong to the Latin-1 character set |
Pa | Pascal | |
Siemens | Siemens | The SI name S would conflict with s (seconds) defined in the package Measures. Therefore the full name is used instead |
Sv | Sievert | |
Tesla | Tesla | The short name t is reserved for metric ton |
V | Volt | |
W | Watt | |
Wb | Weber |
The package Float_Measures_Derived is an instance of Measures_Derived for the standard type Float.
Further constants are defined in the generic package Measures_Irregular:
generic
with package Derived_Measures is new Measures_Derived (<>);
package Measures_Irregular is ...
The package provides constants corresponding to various
irregular units:
Constant | Unit of measurement |
acre | Acre |
ang | Ångström |
are | Are |
atm | Athmosphere |
B | Bel |
BTU | British thermal unit |
Bq | Becquerel |
bar | Bar |
barleycorn | Barleycorn |
barn | Barn |
barrel | Barrel |
Ci | Curie |
cal | Calorie |
candle | Candle |
carat | Carat |
Celsius | Degree of Celsius |
ch | Chain |
cubit | Cubit |
d | Day |
dB | Decibel |
degree | Degree (plane angle) |
dyn | Dyn |
eV | Electronvolt |
ell | Ell |
erg | Erg |
Fahrenheit | Degree of Fahrenheit |
fathom | Fathom |
finger | Finger |
ft | Foot |
fpm | Feet per minute |
fps | Feet per second |
fur | Furlong |
G | Gauss |
gal | Gallon |
grain | Grain |
gram | Gram. The SI unit for mass is kilogram |
h | Hour |
hand | Hand |
hectare | Hectare |
hp | Horsepower |
INM | International nautical mile |
inch | Inch |
kcal | Kilocalorie |
kgf | Kilogram-force |
knot | Knot |
L | Liter |
lb | Pound |
line | Line |
link | Link |
ly | Light year |
mi | Mile |
min | Minute |
min_of_arc | Minute of arc |
mpg | Miles per gallon |
mph | Miles per hour |
mps | Miles per second |
nail | Nail |
Oe | Oersted |
oz | Ounce |
pace | Pace |
pc | Parsec |
percent | Percent |
point | Point |
ppb | Parts per billion |
ppm | Parts per million |
ppt | Parts per trillion |
psi | Pounds per square inch |
pt | Pint |
qt | Quart |
R | Roentgen |
rd | Rod |
rood | Rood |
rpm | Revolutions per minute |
rps | Revolutions per second |
sec_of_arc | Second of arc |
span | Span |
t | Metric ton |
tablespoon | Table spoon |
teaspoon | Tea spoon |
torr | Torr (mmHg) |
township | Township |
u | Unified atomic mass |
ua | Astronomical unit |
wineglass | Wine glass |
yd | Yard |
year | Year |
The package Float_Measures_Irregular is an instance of Measures_Irregular for the type Float.
The generic package Measures_Elementary_Functions
generic
type Number is digits <>;
with package The_Measures is new Measures (Number);
package Measures_Elementary_Functions is
...
provides the following functions:
function Sqrt (X : Measure) return Measure;
The function Sqrt is defined for the measures which unit has components with
even exponent part. The exception Unit_Error is propagated otherwise. For
instance:
Area : Measure := 25.0 * m**2;
Side : Measure;
. . .
Side := Sqrt (Area); -- OK, the result is 5 m
Side := Sqrt (Side); -- Error, Unit_Error propagates
Exponent and log functions require a dimensionless argument. The result is
also dimensionless. Note that integer exponentiation is defined for all unshifted
measures.
function Exp (X : Dimensionless) return Dimensionless;
function Log (X : Dimensionless) return Dimensionless;
function Log (X : Dimensionless; Base : Number'Base)
return Dimensionless;
function "**" (Left : Dimensionless; Right : Dimensionless)
return Dimensionless;
function "**" (Left : Dimensionless; Right : Number'Base)
return Dimensionless;
function "**" (Left : Number'Base; Right : Dimensionless)
return Dimensionless;
The trigonometric functions:
function Sin (X : Dimensionless) return Dimensionless;
function Cos (X : Dimensionless) return Dimensionless;
function Tan (X : Dimensionless) return Dimensionless;
function Cot (X : Dimensionless) return Dimensionless;
The argument of trigonometric functions is measured in radians (dimensionless).
No variants with the parameter Cycle as in
Ada.Numerics.Generic_Elementary_Functions are necessary, because arguments
in degrees can be naturally expressed using units:
Cos (180.0 * degree); -- degree is declared in Measures_Irregular
Cos (3.1415 * rad);
The inverse trigonometric functions return the result measured in radians:
function Arcsin (X : Dimensionless) return Dimensionless;
function Arccos (X : Dimensionless) return Dimensionless;
function Arctan (X : Dimensionless) return Dimensionless;
function Arccot (X : Dimensionless) return Dimensionless;
function Arctan (Y, X : Measure) return Dimensionless;
function Arccot (X, Y : Measure) return Dimensionless;
Arctan and Arccot are defined for any pair of compatible unshifted measures (Unit_Error is propagated otherwise). For instance:
subtype Height is Measure (Length);
subtype Width is Measure (Length);
X : Width;
Y : Height;
Angle : Dimensionless; -- Radians
. . .
X := 25.0 * m;
Y := 30.1 * ft; -- ft (foot) is declared in Measures_Irregular
Angle := Arctan (Y, X);
Hyperbolical functions are defined on dimensionless argument:
function Sinh (X : Dimensionless) return Dimensionless;
function Cosh (X : Dimensionless) return Dimensionless;
function Tanh (X : Dimensionless) return Dimensionless;
function Coth (X : Dimensionless) return Dimensionless;
function Arcsinh (X : Dimensionless) return Dimensionless;
function Arccosh (X : Dimensionless) return Dimensionless;
function Arctanh (X : Dimensionless) return Dimensionless;
function Arccoth (X : Dimensionless) return Dimensionless;
The package instance for the type Float is named Float_Measures_Elementary_Functions.
There are two encoding-specific generic packages responsible conversions of Measure to and from strings and one universal generic package for handling any encoding. The package Measures_Edit and the package Measures_UTF8_Edit are encoding-specific. Both packages have same formal parameters:
generic
with package Irregular_Measures is new Measures_Irregular (<>);
with package Float_Edit is
new Strings_Edit.Float_Edit
( Irregular_Measures.Derived_Measures.Measures.Number
);
package Measures_[UTF8_]Edit is ...
The package Measures_Edit is used for dealing with strings encoded in either ASCII or Latin-1 character sets. The package Measures_UTF8_Edit is used for the strings encoded in UTF-8 (see Unicode Transformation Format). The routines provided by the packages are almost identical and differ only the sets of symbols supported. (The packages Float_Measures_Edit and Float_Measures_UTF8_Edit are instantiations of Measures_Edit and Measures_UTF8_Edit for the standard type Float.)
The following subroutines are used for measures
input:
procedure Measures_Edit.Get
( Source : String;
Pointer : in out Integer;
Value : out Measure;
Latin1 : Boolean := True
);
procedure Measures_UTF8_Edit.Get
( Source : String;
Pointer : in out Integer;
Value : out Measure
);
The procedures Get input a measure from the string Source. The process starts from the Source (Pointer) position. After successful completion Pointer is advanced to the position following the measure taken from the string. The parameter Value accepts the measure. The flag Latin1 of Measures_Edit.Get indicates Latin-1 character set support. With Latin1 = true the set of recognized symbols is extended as shown in the table below. The variant Measures_UTF8_Edit.Get is used for UTF-8 encoded strings. It supports an even larger set of symbols:
Character | Latim-1 | UTF-8 | Code point | Meaning |
0 | - | E216 8116 B016 | 207016 | Power 0 |
1 | B916 | C216 B916 | 00B916 | Power 1 |
2 | B216 | C216 B216 | 00B216 | Power 2 |
3 | B316 | C216 B316 | 00B316 | Power 3 |
4 | - | E216 8116 B416 | 207416 | Power 4 |
5 | - | E216 8116 B516 | 207516 | Power 5 |
6 | - | E216 8116 B616 | 207616 | Power 6 |
7 | - | E216 8116 B716 | 207716 | Power 7 |
8 | - | E216 8116 B816 | 207816 | Power 8 |
9 | - | E216 8116 B916 | 207916 | Power 9 |
+ | - | E216 8116 BA16 | 207A16 | Power + |
- | - | E216 8116 BB16 | 207B16 | Power - |
· | B716 | C216 B716 | 00B716 | Multiplication operator |
° | B016 | C216 B016 | 00B016 | Degree, also in °C, °F etc |
µ | B516 | C216 B516 | 00B516 | Micro |
CE16 BC16 | 03BC16 | |||
°C | - | E216 8416 8316 | 210316 | Celsius (one letter sign) |
°F | - | E216 8416 AA16 | 210916 | Fahrenheit (one letter sign) |
K | - | E216 8416 AA16 | 212A16 | K (Kelvin, one letter sign) |
Å | - | E216 8416 AB16 | 212B16 | Ångström (one letter sign) |
Å | C516 | C316 8516 | 00C516 | Å in Ångström |
å | E516 | C316 A516 | 00E516 | Small Å in Ångström |
ö | F616 | C316 B616 | 00F616 | Small O-umlaut in Ångström |
Ω | - | CE16 A916 | 03A916 | Ohm |
E216 8416 A616 | 212616 |
The measure syntax is:
<measure> ::= ( <measure> ) <measure> ::= <measure> [<dyadic-operation>] <measure> <measure> ::= <prefix-operation><measure> <measure> ::= <measure><postfix-operation> <measure> ::= <number> <measure> ::= <unit> <dyadic-operation> ::= ** | ^ | * | · | / | + | - | and <prefix-operation> ::= + | - <postfix-operation> ::= <superscript-integer>
Space and tabs can be used as delimiters. Two consequent lexemes shall be
separated by at least one delimiter if the first one ends with a letter while
the second starts with a letter. For instance:
As Illegal, there is no any delimiter between A and s A s OK, A*s A·s OK, A*s 5A OK, 5*A
The exponentiation operation (** or
^) has the highest priority. Then the multiplication
(*,
· or empty)
follows. The division (/) has lower priority
than the multiplication, therefore kg/m*s is an equivalent to kg/(m*s). The
lowest priority has the shift (and). The right
argument of the exponentiation operation should be dimensionless and have
zero fraction, i.e. be convertible to an integer without a precision loss. <superscript-integer>
is recognized only in UTF-8 variant and when Latin1 = true,
but then only the powers 1, 2 and 3 are supported. <unit> is a name denoting
a measurement unit, such as foot:
<unit> ::= <short-regular-unit> | <full-regular-unit> | <irregular-unit> <short-regular-unit> ::= [<short-SI-prefix>] <short-unit-name> <full-regular-unit> ::= [<full-SI-prefix>] <full-unit-name>
The following table defines
<short-unit-name> and
<full-unit-name>. Beware,
all names are case sensitive:
Short name(s) | Full name(s) | Comments |
A | ampere | |
bar | ||
B | bel | |
barn | barn | |
Bq | becquerel | |
C | coulomb | |
°C | In Latin-1 and UTF-8 encoded strings a combination of ring (00B016) and the capital letter C can be used. In UTF-8 the degree Celsius (210316) is also supported | |
cd | candela | |
Ci | curie | |
erg | erg | |
F | farad | |
G | gauss | |
g | gram, grams, gramme, grammes | |
Gy | gray | |
H | henry | |
Hz | hertz | |
J | joule | |
K | kelvin | In UTF-8 encoded strings, Kelvin sign (212A16) is recognized as well |
L, l | liter, liters, litre, litres | |
lm | lumen | |
lx | lux | |
m | meter, meters, metre, metres | |
mol | mole | |
N | newton | |
Ω | ohm, Ohm | In UTF-8 encoded strings both Unicode Greek omega (03A916) and the Ohm (212616) sign are recognized |
Pa | pascal | |
R | roentgen | |
rad | radian | |
S | siemens | |
s | second, seconds | |
sr | steradian | |
Sv | sievert | |
T | tesla | |
t | ton, tons, tonne, tonnes | |
V | volt | |
W | watt | |
Wb | weber |
Any regular unit name can be used with a SI prefix. The following table defines
<short-SI-prefix> and
<full-SI-name> (all names
are case sensitive):
Short | Full | Multiplicand | Comments |
Y | yotta | 1024 | |
Z | zetta | 1021 | |
E | exa | 1018 | |
P | petta | 1015 | |
T | tera | 1012 | |
G | giga | 109 | |
M | mega | 106 | |
k | kilo | 103 | |
h | hecto | 102 | |
da | deka | 101 | |
d | deci | 10-1 | |
c | centi | 10-2 | |
m | milli | 10-3 | |
µ | micro | 10-6 | This prefix (00B516) is only recognized in Latin-1 and UTF-8. The latter additionally does Greek mu (03BC16) |
n | nano | 10-9 | |
p | pico | 10-12 | |
f | femto | 10-15 | |
a | atto | 10-18 | |
z | zepto | 10-21 | |
y | yocto | 10-24 |
Note that short prefixes are used with short names, full prefixes are used
with full names. For instance, the only legal notations of km are: km,
kilometer, kilometre, kilometers, kilometres.
The irregular unit names
(<irregular-unit>) cannot
be used with SI prefixes. They are (all names are case sensitive):
Name(s) | Meaning | Comments |
% | Percent | |
' | Minute of arc | |
" | Second of arc | |
°, degree, degrees | Degree | Ring (00B016) is recognized only In Latin-1 and UTF-8 encoded strings |
°F, Fahrenheit | Degree of Fahrenheit | In Latin-1 and UTF-8 encoded strings a combination of ring (00B016) and the capital letter F can be used. Additionally, in UTF-8 degree Fahrenheit is recognized (210916) |
°K, Kelvin | Degree of Kelvin | In Latin-1 and UTF-8 encoded strings a combination of ring (00B016) and the capital letter K can be used. Names K and kelvin are regular (can be used with a SI prefix). In UTF-8 Kelvin sign (212A16) is also regular. |
Å, Ångström, ångström | Ångström | Letters with accents are supported only in Latin-1 and UTF-8. Additionally in UTF-8 the angstrom sign (212B16) is recognized |
a., acre, acres | Acre | |
are, ares | Are | |
atm, atmosphere, atmospheres | Atmosphere | |
barleycorn, barleycorns | Barleycorn | |
bbl, barrel, barrels | Barrel | |
BTU, Btu, btu | British thermal unit | |
c, carat, carats | Carat | |
cal, calorie, calories | Calorie | |
candle, candles | Candle | |
Celsius | Degree of Celsius | The short form of Celsius degree (°C) is regular and can be used with short SI prefixes. Therefore, the expression m°C is legal and means one thousandth part of °C i.e. (0.001 + 273.15) K. |
ch, chain, chains | Chain | |
cubit, cubits | Cubit | |
d, day, days | Day | |
dyn, dyne | Dyne | |
ell, ells | Ell | |
eV | Electronvolt | |
f, fathom, fathoms | Fathom | |
foot, feet | Foot | Note that the commonly used abbreviation ft conflicts with metric ton: ft=femtoton=10-12kg |
finger, fingers | Finger | |
fpm | Feet per minute | |
fps | Feet per second | |
fur, furlong, furlongs | Furlong | |
gal, gallon, gallons | Gallon | |
grain, grains | Grain | |
h, hour, hours | Hour | |
hand, hands | Hand | |
hectare, hectares | Hectare | |
hp, horsepower | Horsepower | |
in., inch, inches | Inch | |
INM | International Nautical Mile | |
Kcal, kcal | Kilocalorie | |
kgf, kilogram-force | Kilogram-force | |
knot, knots | Knot | |
lb, pound, pounds | Pound | |
line, lines | Line | |
link, links | Link | |
liqpt, liquidpint | Liquid pint | |
ly, lightyear, lightyears | Lightyear | |
mi, mile, miles | Mile | |
min, minute, minutes | Minute | |
mmHg | Torr | |
mpg | Miles per gallon | |
mph | Miles per hour | |
mps | Miles per second | |
nail, nails | Nail | |
Oe, oersted | Oersted | |
oz, ounce, ounces | Ounce | |
pace, paces | Pace | |
pc, parsec, parsecs | Parsec | |
point, points | Point | |
ppb | Parts per billion | |
ppm | Parts per million | |
ppt | Parts per trillion | |
PSI, psi | Pounds per square inch | |
pt, pint, pints | Pint | |
qt, quart, quarts | Quart | |
rd, rod, rods | Rod | |
rood, roods | Rood | |
rpm | Revolutions per minute | |
rps | Revolutions per second | |
sec | Second | Names s, second and seconds are regular (can be used with a SI prefix) |
span, spans | Span | |
tablespoon, tablespoons | Tablespoon | |
teaspoon, teaspoons | Teaspoon | |
torr | Torr | |
township, townships | Township | |
u | Unified atomic mass | |
ua | Astronomical unit | |
wineglass, wineglasses | Wineglass | |
yd, yard, yards | Yard | |
year, years | Year |
Examples:
34.5 * mm 65·km/h 65 km/h 65km/h 65 km/h K and 273.15 degree Celsius yd^2 one square yard lb·yd²/s² use of Latin-1 superscripts
Constraint_Error | Numeric error in unit expression |
Data_Error | Syntax error |
End_Error | There is no measure in the string |
Layout_Error | The value of Pointer is not in the range Source'First..Source'Last+1 |
Unit_Error | Illegal unit expression (like m/°C) |
procedure Measures_Edit.Get_Unit
( Source : String;
Pointer : in out Integer;
Value : out Measure;
Latin1 : Boolean := True
);
procedure Measures_UTF8_Edit.Get_Unit
( Source : String;
Pointer : in out Integer;
Value : out Measure
);
These procedures are restricted variant of the corresponding Gets. They recognize only measure units such as foot or meter. Irregular units and units with SI prefixes are recognized as well. No numbers or unit operations are recognized. Blanks are not skipped. This can be useful in syntax analyzers that may have different rules about operations and spaces. Such analyzer would rather use Get_Unit and then apply unit arithmetic for the operations it recognize. The meaning of the parameters is same as described for Get.
Data_Error | Syntax error |
End_Error | There is no measure in the string |
Layout_Error | The value of Pointer is not in the range Source'First..Source'Last+1 |
function Measures_Edit.Value
( Source : String;
Latin1 : Boolean := True
) return Measure;
function Measures_UTF8_Edit.Value
( Source : String
) return Measure;
These functions get the measure from the string Source. They are simplified versions of the corresponding Get-procedures. The whole string should be matched. Otherwise the exception Data_Error is propagated. The following exceptions are propagated out of the functions:
Constraint_Error | Numeric error in unit expression |
Data_Error | Syntax error |
End_Error | There is no measure in the string Source |
Unit_Error | Illegal unit expression (like m/°C) |
The packages Measures_Edit and Measures_UTF8_Edit provide the following subroutines for measures output:
procedure Measures_Edit.Put
( Destination : in out String;
Pointer : in out Integer;
Value : Measure;
Latin1 : Boolean := True;
Derived : Boolean := True;
RelSmall : Positive := Strings_Edit.MaxSmall;
AbsSmall : Integer := -Strings_Edit.MaxSmall;
Field : Natural := 0;
Justify : Strings_Edit.Alignment := Strings_Edit.Left;
Fill : Character := ' '
);
procedure Measures_UTF8_Edit.Put
( Destination : in out String;
Pointer : in out Integer;
Value : Measure;
Derived : Boolean := True;
RelSmall : Positive := Strings_Edit.MaxSmall;
AbsSmall : Integer := -Strings_Edit.MaxSmall
);
These procedures place the measure specified by the parameter Value
into the output string Destination. The string is written starting
from Destination (Pointer). The procedure from the package Measures_Editt
has the parameter Latin1, which when true, allows
using of Latin-1 characters listed in the table
above, otherwise the output is done in ASCII. The procedure from the package Measures_UTF8_Edit uses
UTF-8 encoded characters from the table. In
all cases only the
code positions in the table having white
background are used in output. So for example in UTF-8 for Ohm,
Greek omega is used rather than the Ohm sign. The parameter Derived if true, allows
derived SI units (such as N, F etc.) to appear in the output. Only plain derived
units do. The parameters RelSmall
and AbsSmall specify the precision of numeric output (see
Strings_Edit.Float_Edit for further information). The procedure from the
package Measures_Edit
has additional optional parameters Field, Justify, Fill. When the parameter
Field is not zero then Justify specifies alignment and
Fill is the character used for filling. When Field is greater than
Destination'Last - Pointer + 1, the latter is used instead. The
UTF-8 variant from the package Measures_UTF8_Edit
does not have these parameters because they would be meaningless for a UTF-8
encoded output. After successful completion Pointer is advanced to the first character
following the output or to Destination'Last + 1. A measure can be output
in one of the following forms:
Format | Measure type | Example |
<gain> | Unshifted, dimensionless (a number) | 25.7 |
<unit> | Unshifted, Gain = 1 (a SI unit) | m/s |
<gain>*<unit> | Unshifted | 25.7·W |
<gain> and <offset> | Shifted, dimensionless | 4.1 and 6.4 |
<unit> and <offset> | Shifted, Gain = 1 | K and 273.15 |
<gain>*<unit> and <offset> | Shifted | 35.08·K and 273.15 |
For instance:
Text : String (1..80);
Pointer : Positive := 1;
. . .
Put (Text, Pointer, 25.0*N, Derived => False, AbsSmall => 0);
will put 25·kg·m/s² into the string Text starting from the position 1. The parameter Derived=false forbids use of N (newton) in the output. Otherwise the result would be 25·N. The parameter AbsSmall=0 tells that the value has the precision ±0.5·10AbsSmall-1, so only the digits before the decimal point are output. For further information about floating-point I/O see the description of the package Strings_Edit.
Layout_Error | Pointer is not in Destination'Range or there is no room for the output |
function Measures_Edit.Image
( Value : Measure;
Latin1 : Boolean := True;
Derived : Boolean := True;
RelSmall : Positive := Strings_Edit.MaxSmall;
AbsSmall : Integer := -Strings_Edit.MaxSmall
) return String;
function Measures_UTF8_Edit.Image
( Value : Measure;
Derived : Boolean := True;
RelSmall : Positive := Strings_Edit.MaxSmall;
AbsSmall : Integer := -Strings_Edit.MaxSmall
) return String;
The functions Image convert the parameter Value to string. The parameters Latin1, Derived, RelSmall and AbsSmall have same meaning as in Put (see).
The generic package Measures_Universal_Edit provides unified subroutines for string I/O with arbitrary encodings:
generic
with package Irregular_Measures is new Measures_Irregular (<>);
with package Float_Edit is
new Strings_Edit.Float_Edit
( Irregular_Measures.Derived_Measures.Measures.Number
);
package Measures_Universal_Edit is ...
The package provides a set of subroutines similar to ones of Measures_Edit and Measures_UTF8_Edit.
They differs from the corresponding subroutines of these package in one
additional parameter Mode, which for each subroutine determines the
character set to be used.
procedure Get
( Source : String;
Pointer : in out Integer;
Value : out Measure;
Mode : Code_Set
);
procedure Get_Unit
( Source : String;
Pointer : in out Integer;
Value : out Measure;
Mode : Code_Set
);
function Image
( Value : Measure;
Mode : Code_Set;
Derived : Boolean := True;
RelSmall : Positive := Strings_Edit.MaxSmall;
AbsSmall : Integer := -Strings_Edit.MaxSmall
) return String;function Value
( Source : String;
Mode : Code_Set
) return Measure;
procedure Put
( Destination : in out String;
Pointer : in out Integer;
Value : Measure;
Mode : Code_Set;
Derived : Boolean := True;
RelSmall : Positive := Strings_Edit.MaxSmall;
AbsSmall : Integer := -Strings_Edit.MaxSmall
);
The parameter Mode has the enumeration type Code_Set. The meaning of the values is as follows:
This package has a non-generic instance Float_Measures_Universal_Edit for the measures based on the standard type Float.
Two separate sets of packages implement the types Unit and the type Measure. There is also a set of supporting packages used internally.
The packages related to the type Unit:
Package | Provides | |
Units | The type Unit, unit arithmetic | |
Base | The constants corresponding to the base SI units | |
Constants | The constants corresponding to some physical entities | |
Edit | Conversion to ASCII and Latin-1 strings | |
UTF8_Edit | Conversion to UTF-8 encoded strings |
The following packages are related to the type Measure:
Package (generic) | Provides | Non-generic version (Float) |
Measures | The type Measure, measure arithmetic, constants corresponding to the base SI units. | Float_Measures |
Measures_Derived | The constants corresponding to the derived SI units. | Float_Measures_Derived |
Measures_Edit | Input and output of measures (ASCII and Latin-1 string conversions) | Float_Measures_Edit |
Measures_Elementary_Functions | Elementary functions (sqrt, log, exp etc.) | Float_Measures_Elementary_Functions |
Measures_Irregular | The constants corresponding to some of irregular units | Float_Measures_Irregular |
Measures_Universal_Edit | Input and output of measures using multiple encodings | Float_Measures_Universal_Edit |
Measures_UTF8_Edit | Input and output of measures with UTF-8 encoded strings | Float_Measures_UTF8_Edit |
The following example shows how the generic packages are instantiated:
with Measures;
with Measures_Derived;
with Measures_Irregular;
with Measures_Edit;
with Strings_Edit.Float_Edit;
. . .
type Real is digits ...;
--
-- Instantiation of Measures with the type Real as the parameter
--
package Real_Measures is new Measures (Real);
--
-- Instantiation of Measures_Derived
--
package Real_Measures_Derived is new Measures_Derived (Real_Measures);
--
-- Instantiation Measures_Irregular
--
package Real_Measures_Irregular is
new Measures_Irregular (Real_Measures_Derived);
--
-- Instantiation Measures_Edit
--
package Real_Edit is new Strings_Edit.Float_Edit (Real);
--
-- Instantiation Measures_Edit
--
package Real_Measures_Edit is
new Measures_Derived
( Real_Measures_Irregular,
Real_Edit
);
The software uses the packages Strings_edit and Tables. The following table shows the packages defined for internal use:
Package | Provides |
Measures_Generic_Edit | Generic package for I/O of measures for all types of encodings. Measures_Edit, Measures_UTF8_Edit, Measures_Universal_Edit instantiate it. |
Measures_Table_Of_Integer | The table of SI prefixes (their powers) or unit operations (coded as integers). Instantiates the package Tables with Integer as the parameter. |
Measures_Table_Of_Measure | The table of measurement units. Instantiates the package Tables with Address as the parameter. |
The software uses the packages Strings_edit and Tables. The following table shows the packages defined for internal use:
The file Measures_Test.adb contains a test program for the packages Measures and Units. It also estimates the performance hit when the type Measure is used for calculations instead of Float.
The subdirectory Units-Examples→Units-Converter contains a simple sample program which converts dimensioned values.
The following is the full source code of the converter. It is located in Units-Examples→Units-Converter→Win32. The fragments relevant to dealing with units are highlighted yellow. The rest is dealing with Windows API. The program uses Windows Unicode support. For this measures input and output is performed in UTF-8 format using the package Float_Measures_UTF8_Edit. Note that Windows uses USC-2 encoding therefore all strings are converted from Wide_String to UTF-8 and back using subroutines of the package Strings_Edit.UTF8.Handling.
Implementation, file units_converter.adb:
with
Ada.IO_Exceptions; use Ada.IO_Exceptions; with Ada.Unchecked_Conversion; -- -- Things related to Win32-API -- with Win32; use Win32; with Win32.WinBase; use Win32.WinBase; with Win32.WinDef; use Win32.WinDef; with Win32.WinMain; use Win32.WinMain; with Win32.WinUser; use Win32.WinUser; with Win32.CommCTRL; use Win32.CommCTRL; |
with Float_Measures;
use Float_Measures; with Float_Measures_UTF8_Edit; use Float_Measures_UTF8_Edit; with Strings_Edit.UTF8.Handling; use Strings_Edit.UTF8.Handling; with Units; use Units; |
with Interfaces.C; with System; procedure Units_Converter is -- -- The following are the constants defined in the resource script. See -- Units_Converter.rc file. -- Dialog_ID : constant := 101; Input_ID : constant := 1000; SI_ID : constant := 1001; Base_ID : constant := 1002; Message_ID : constant := 1003; Go_ID : constant := 1004; -- -- Useless windows return codes -- INT_Result : INT; BOOL_Result : BOOL; UINT_Result : UINT; -- -- Dialog_Proc -- Process messages to the dialog box -- -- Window - The window (a handle to) -- Message - To process -- WPar - Its short parameter -- LPar - Its long parameter -- -- Returns : -- -- Message processing code (message specific) -- function Dialog_Proc ( Window : HWND; Message : UINT; WPar : WPARAM; LPar : LPARAM ) return BOOL; pragma Convention (Stdcall, Dialog_Proc); -- -- Dialog_Proc_Access -- Pointer to Dialog_Proc -- type Dialog_Proc_Access is access function ( Window : HWND; Message : UINT; WPar : WPARAM; LPar : LPARAM ) return BOOL; pragma Convention (Stdcall, Dialog_Proc_Access); -- -- To_DLGPROC -- Conversion from Dialog_Proc_Access to DLGPROC -- -- This is necessary to work around access type protection system. -- DLGPROC is declared so that no nested function pointer may be -- converted to it. So we have declared another pointer type and convert -- it to DLGPROC. -- function To_DLGPROC is new Ada.Unchecked_Conversion (Dialog_Proc_Access, DLGPROC); -- -- Get_Text -- Wrapper around windows API function GetDlgItemText -- -- Window - A handle to -- ID - Of the control -- -- Returns : -- -- The text of the control -- function Get_Text (Window : HWND; ID : UINT) return String is Input : WCHAR_Array (1..256); begin UINT_Result := GetDlgItemTextW ( Window, Input_ID, Input (Input'First)'Unchecked_Access, Input'Length ); return To_UTF8 ( Interfaces.C.To_Ada (Interfaces.C.WCHAR_Array (Input)) ); end Get_Text; -- -- Set_Text -- Wrapper around windows API function SetDlgItemText -- -- Window - A handle to -- ID - Of the control -- Text - To be put there -- procedure Set_Text ( Window : HWND; ID : UINT; Text : String ) is Output : WCHAR_Array := WCHAR_Array (Interfaces.C.To_C (To_Wide_String (Text))); begin BOOL_Result := SetDlgItemTextW ( Window, INT (ID), Output (Output'First)'Unchecked_Access ); end Set_Text; |
-- -- Go -- When the Go button gets pressed -- -- Window - A handle to -- procedure Go (Window : HWND) is Number : Measure; begin Set_Text (Window, SI_ID, ""); Set_Text (Window, Base_ID, ""); Set_Text (window, Message_ID, ""); Number := Value (Get_Text (Window, Input_ID)); Set_Text (Window, SI_ID, Image (Number)); Set_Text (Window, Base_ID, Image (Number, Derived => False)); exception when Constraint_Error => Set_Text (Window, Message_ID, "Numeric error"); when Data_Error => Set_Text (Window, Message_ID, "Syntax error"); when End_Error => Set_Text (Window, Message_ID, "Nothing recognized"); when Unit_Error => Set_Text (Window, Message_ID, "Unit error"); end Go; |
-- -- Dialog_Proc -- Implementation -- function Dialog_Proc ( Window : HWND; Message : UINT; WPar : WPARAM; LPar : LPARAM ) return BOOL is begin case Message is when WM_CLOSE => BOOL_Result := EndDialog (Window, 0); when WM_COMMAND => case HIWORD (DWORD (WPar)) is when BN_CLICKED => case LOWORD (DWORD (WPar)) is when Go_ID => Go (Window); when others => null; end case; when others => null; end case; when WM_INITDIALOG => Set_Text ( Window, Message_ID, "Source: www.dmitry-kazakov.de/ada/units.htm" ); when others => null; end case; return 0; end Dialog_Proc; Ptr : Dialog_Proc_Access := Dialog_Proc'Access; Name : CHAR_Array := "RichEd20.dll" & CHAR'Val (0); Handle : HINSTANCE; begin InitCommonControls; -- Needed for Unicode support Handle := LoadLibrary (Name (Name'First)'Unchecked_Access); Int_Result := DialogBoxParam ( Get_hInstance, PCCH (MAKEINTRESOURCE (Dialog_ID)), System.Null_Address, To_DLGPROC (Ptr), 0 ); if 0 = FreeLibrary (Handle) then null; end if; end Units_Converter; |
GTK is a platform independent library for creating graphical applications. It is available for a wide range of platforms which includes Windows and Linux. The following is the full source code of the converter based on GTK. It is located in Units-Examples→Units-Converter→GTK. The fragments relevant to dealing with units are highlighted yellow. The rest is dealing with GTK. Note that GTK natively supports UTF-8, so the package Float_Measures_UTF8_Edit is used without any further translation.
Implementation, file units_converter.adb:
with Ada.Characters.Latin_1;
use
Ada.Characters.Latin_1; with Ada.IO_Exceptions; use Ada.IO_Exceptions; -- -- Things related to Gtk-API -- with Gdk.Event; use Gdk.Event; with Gtk.Enums; use Gtk.Enums; with Gtk.Frame; use Gtk.Frame; with Gtk.Button; use Gtk.Button; with Gtk.GEntry; use Gtk.GEntry; with Gtk.Handlers; use Gtk.Handlers; with Gtk.Label; use Gtk.Label; with Gtk.Table; use Gtk.Table; with Gtk.Widget; use Gtk.Widget; with Gtk.Window; use Gtk.Window; with Gtk.Main; |
with Float_Measures;
use Float_Measures; with Float_Measures_UTF8_Edit; use Float_Measures_UTF8_Edit; with Units; use Units; |
procedure Units_Converter
is package Handlers is new Gtk.Handlers.Callback (Widget_Type => Gtk_Widget_Record); package Return_Handlers is new Gtk.Handlers.Return_Callback ( Widget_Type => Gtk_Widget_Record, Return_Type => Boolean ); function Delete_Event ( Widget : access Gtk_Widget_Record'Class; Event : Gdk_Event ) return Boolean is begin return False; end Delete_Event; procedure Destroy (Widget : access Gtk_Widget_Record'Class) is begin Gtk.Main.Main_Quit; end Destroy; -- -- Read_Only_Text -- Sunken labels -- type Read_Only_Text is record Text : Gtk_Label; Frame : Gtk_Frame; end record; -- -- Gtk_New -- Initializes the label -- procedure Gtk_New ( Text : in out Read_Only_Text; Label : String := "" ) is begin Gtk_New (Text.Frame); Set_Shadow_Type (Text.Frame, Shadow_In); Gtk_New (Text.Text, Label); Set_Alignment (Text.Text, 0.0, 0.5); Add (Text.Frame, Text.Text); end Gtk_New; -- -- Show -- The label -- procedure Show (Text : in out Read_Only_Text) is begin Show (Text.Text); Show (Text.Frame); end Show; Window : Gtk_Window; Grid : Gtk_Table; Label1 : Gtk_Label; Label2 : Gtk_Label; Label3 : Gtk_Label; Value_To_Convert : Gtk_Entry; Value_In_SI : Gtk_Entry; Value_In_Base_Units : Gtk_Entry; Button : Gtk_Button; Message : Read_Only_Text; |
-- -- Go -- When the Go button gets pressed -- -- Widget - The button -- procedure Go (Widget : access Gtk_Widget_Record'Class) is Number : Measure; begin Set_Text (Value_In_SI, ""); Set_Text (Value_In_Base_Units, ""); Set_Text (Message.Text, ""); Number := Value (Get_Text (Value_To_Convert)); Set_Text (Value_In_SI, Image (Number)); Set_Text ( Value_In_Base_Units, Image (Number, Derived => False) ); exception when Constraint_Error => Set_Text (Message.Text, "Numeric error"); when Data_Error => Set_Text (Message.Text, "Syntax error"); when End_Error => Set_Text (Message.Text, "Nothing recognized"); when Unit_Error => Set_Text (Message.Text, "Unit error"); end Go; |
begin -- -- Initialization -- Gtk.Main.Init; -- -- Creating the main window and handle its events -- Gtk.Window.Gtk_New (Window); Set_Title (Window, "Unit conversion (Ada95 GTK+)"); Return_Handlers.Connect ( Window, "delete_event", Return_Handlers.To_Marshaller (Delete_Event'Access) ); Handlers.Connect ( Window, "destroy", Handlers.To_Marshaller (Destroy'Access) ); Gtk.Window.Set_Border_Width (Window, 10); -- -- Creating the grid, a table to align all other widgets -- Gtk_New (Grid, 3, 4, False); Set_Row_Spacings (Grid, 3); Set_Col_Spacings (Grid, 3); Gtk.Window.Add (Window, Grid); -- -- The left column are labels -- Gtk_New (Label1, "Value to convert" & LF & "For example 23.5 bar"); Attach_Defaults (Grid, Label1, 0, 1, 0, 1); Set_Justify (Label1, Justify_Right); Set_Alignment (Label1, 1.0, 0.5); Gtk_New (Label2, "SI equivalent"); Attach_Defaults (Grid, Label2, 0, 1, 1, 2); Set_Alignment (Label2, 1.0, 0.5); Gtk_New (Label3, "Base units only"); Attach_Defaults (Grid, Label3, 0, 1, 3, 4); Set_Alignment (Label3, 1.0, 0.5); -- -- The central column is the edit fields -- Gtk_New (Value_To_Convert); Handlers.Connect ( Value_To_Convert, "activate", Handlers.To_Marshaller (Go'Access) ); Attach_Defaults (Grid, Value_To_Convert, 1, 2, 0, 1); Gtk_New (Value_In_SI); Set_Sensitive (Value_In_SI, False); Attach_Defaults (Grid, Value_In_SI, 1, 2, 1, 2); Gtk_New (Value_In_Base_Units); Attach_Defaults (Grid, Value_In_Base_Units, 1, 2, 3, 4); -- -- The right column is the button Go -- Gtk_New (Button, " Go "); Handlers.Connect ( Button, "clicked", Handlers.To_Marshaller (Go'Access) ); Attach_Defaults (Grid, Button, 3, 4, 0, 4); -- -- Error messages is beneath -- Gtk_New (Message, "Source: www.dmitry-kazakov.de/ada/units.htm"); Attach_Defaults (Grid, Message.Frame, 0, 4, 4, 5); -- -- Show everything -- Show (Label1); Show (Value_To_Convert); Show (Button); Show (Label2); Show (Value_In_SI); Show (Label3); Show (Value_In_Base_Units); Show (Message); Show (Grid); Show (Window); -- -- Enter the events processing loop -- Gtk.Main.Main; end Units_Converter; |
To compile this example you will need GTK, and GtkAda bindings installed.
The current version was tested with Gnat 3.15p compiler.
Changes to the version 1.8:
Changes to the version 1.7:
Changes to the version 1.6:
Changes to the version 1.5:
Changes to the version 1.4:
Changes to the version 1.3:
Foreword
1. Types
1.1. The type Unit
1.1.1. Base units
1.1.2. Unit constants
1.1.3. Conversion to ASCII and Latin-1 strings
1.1.4. Conversion to UTF-8 encoded strings
1.1.5. Design notes
1.2. The type Measure
1.2.1. Shifted and unshifted Measures
1.2.2. Operations defined on Measures
1.2.3. Unit conversions
1.2.4. Constants
1.2.5. Elementary functions
1.2.6. Conversion from String
1.2.7. Conversion to String
1.2.8. Handling I/O in multiple encodings
2. Packages
2.1. The packages related to the type Unit
2.2. The packages related to the type Measure
2.3. Packages defined for internal
use
3. Examples
3.1 Self test
3.2 Unit converter
4. Changes log
5. Table of contents