Unit conversion in LibreOffice code
LibreOffice handles different input and output formats, and also displays text and graphics alongside inside the GUI on computer displays. This requires LibreOffice to understand various different measurement units, and convert values from one to another.
The unit conversion can be done manually, where one should know the units, and calculate factor to convert them to each other.
For example, consider that we want to convert width from points into 1/100 mm, which is used in page setup.
We know that:
1 point = 1/72 inch
1 inch = 25.4 mm = 25400 microns
factor = 25400/(72*10) ≈ 35.27777778
Then, it is possible to write the conversion as:
static int PtTo10Mu( int nPoints ) { return static_cast<int>((static_cast<double>(nPoints)*35.27777778)+0.5); }
A separate function that casts integer nPoints to double, then multiplies it by the factor which has 8 decimal points, and then rounds the result by adding 0.5 and then truncates it and stores it in an integer. This approach is not always desirable. It is error-prone, and lacks enough accuracy. For big values, it can calculates values off by one.
Another approach is to use o3tl (OpenOffice.org template library) convert function. It is as simple as writing:
int nResult = o3tl::convert(nPoint, o3tl::Length::pt, o3tl::Length::mm100)
As you can see, it is much cleaner, and gives the output, properly rounded as an integer!
You need a double? No problem! You can use appropriate template to achieve that:
double fResult = o3tl::convert<double>(nPoint, o3tl::Length::pt, o3tl::Length::mm100)
These are the supported units, defined in the header include/o3tl/unit_conversion.hxx:
mm100 – 1/100th mm = 1 micron
mm10 – 1/10 mm
mm – millimeter
cm – centimeter
m – meter
km – kilometer
emu – English Metric Unit (1/360000 cm)
twip – Twentieth of a point (1/20 pt)
pt – Point (1/72 in)
pc – Pica (1/6 in)
in1000 – 1/1000 in
in100 – 1/100 in
in10 – 1/10 in
in – inch
ft – foot
mi – mile
master – PPT Master Unit (1/576 in)
px – Pixel unit (15 twip, 96 ppi)
ch – Char unit (210 twip, 14 px)
line – Line unit (312 twip)
Handling Overflows
If you are doing a conversion, it is possible that the result overflows. With o3tl::convert() you can handle it this way:
sal_Int64 width = o3tl::convert(nPoint, o3tl::Length::pt, o3tl::Length::mm100, overflow, 0); if (overflow) { ... }
Final Words
Using o3tl::convert() not only simplifies the unit conversion, but it also improves the accuracy. There is a possibility to handle overflow, which is not easily possible if you do the conversion manually. Therefore, unit conversion using this function is usually the best option in LibreOffice.