[Libreoffice-commits] core.git: cui/source emfio/source include/o3tl include/oox include/svtools include/tools o3tl/CppunitTest_o3tl_tests.mk o3tl/qa oox/source sax/source sc/source sd/qa sd/source sfx2/source svtools/source svx/source sw/source vcl/source

Mike Kaganski (via logerrit) logerrit at kemper.freedesktop.org
Sun Feb 14 11:50:45 UTC 2021


 cui/source/tabpages/chardlg.cxx                     |    8 
 cui/source/tabpages/grfpage.cxx                     |   17 
 emfio/source/reader/wmfreader.cxx                   |    5 
 include/o3tl/unit_conversion.hxx                    |  231 +++++
 include/oox/drawingml/drawingmltypes.hxx            |   16 
 include/svtools/unitconv.hxx                        |    2 
 include/tools/UnitConversion.hxx                    |  136 ++-
 o3tl/CppunitTest_o3tl_tests.mk                      |    1 
 o3tl/qa/test-unit_conversion.cxx                    |  872 ++++++++++++++++++++
 oox/source/drawingml/diagram/diagram.cxx            |   11 
 oox/source/drawingml/diagram/diagramlayoutatoms.cxx |   24 
 oox/source/drawingml/drawingmltypes.cxx             |    5 
 oox/source/drawingml/shape.cxx                      |   14 
 oox/source/vml/vmlformatting.cxx                    |   28 
 sax/source/tools/converter.cxx                      |  585 ++-----------
 sc/source/filter/oox/unitconverter.cxx              |   23 
 sc/source/ui/vba/vbarange.cxx                       |   12 
 sd/qa/unit/export-tests-ooxml1.cxx                  |    4 
 sd/qa/unit/export-tests-ooxml2.cxx                  |    4 
 sd/qa/unit/import-tests.cxx                         |    4 
 sd/source/ui/unoidl/unomodel.cxx                    |    7 
 sfx2/source/view/lokcharthelper.cxx                 |    5 
 svtools/source/misc/unitconv.cxx                    |  445 ----------
 svx/source/customshapes/EnhancedCustomShape3d.cxx   |    4 
 svx/source/svdraw/svdmodel.cxx                      |   98 --
 svx/source/svdraw/svdtrans.cxx                      |  165 +--
 sw/source/core/view/viewsh.cxx                      |    6 
 sw/source/filter/html/css1atr.cxx                   |   81 -
 sw/source/filter/ww8/docxattributeoutput.cxx        |    9 
 sw/source/filter/ww8/wrtw8esh.cxx                   |    5 
 sw/source/filter/ww8/ww8par6.cxx                    |    7 
 vcl/source/control/field.cxx                        |  116 --
 vcl/source/gdi/pdfwriter_impl2.cxx                  |   13 
 vcl/source/outdev/bitmap.cxx                        |    9 
 vcl/source/outdev/map.cxx                           |  166 +--
 35 files changed, 1641 insertions(+), 1497 deletions(-)

New commits:
commit cfff893b9c82843a90aac4ecdb3a3936721b74a0
Author:     Mike Kaganski <mike.kaganski at collabora.com>
AuthorDate: Sat Feb 13 13:55:22 2021 +0300
Commit:     Mike Kaganski <mike.kaganski at collabora.com>
CommitDate: Sun Feb 14 12:50:01 2021 +0100

    Move unit conversion code to o3tl, and unify on that in more places
    
    This also allows to easily add more units, both of length and for other
    unit categories.
    
    The conversion for "Line" unit (312 twip) is questionable. Corresponding
    entries in aImplFactor in vcl/source/control/field.cxx were inconsistent
    (45/11 in; 10/13 pc; 156/10 pt). They were added without explanation in
    commit c85db626029fd8a5e0dfcb312937279df32339a0. I haven't found a spec
    of the unit (https://en.wikipedia.org/wiki/Line_(unit) is not specific).
    I used the definition based on "by pt", "by mm/100", "by char" (they all
    were consistent); "by pc" seems inverted; "by twip" was half as much.
    This accepted conversion makes unit test for tdf#79236 pass.
    
    Change-Id: Iae5a21d915fa8e934a1f47f8ba9f6df03b79a9fd
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/110839
    Tested-by: Mike Kaganski <mike.kaganski at collabora.com>
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>

diff --git a/cui/source/tabpages/chardlg.cxx b/cui/source/tabpages/chardlg.cxx
index a7e3dda42bc9..6a35b45ba46f 100644
--- a/cui/source/tabpages/chardlg.cxx
+++ b/cui/source/tabpages/chardlg.cxx
@@ -59,6 +59,7 @@
 #include <FontFeaturesDialog.hxx>
 #include <sal/log.hxx>
 #include <osl/diagnose.h>
+#include <o3tl/unit_conversion.hxx>
 
 using namespace ::com::sun::star;
 
@@ -441,7 +442,9 @@ namespace
             // old value, scaled
             tools::Long nHeight;
             if ( _pFontSizeLB->IsPtRelative() )
-                nHeight = rOldItem.GetHeight() + PointToTwips( static_cast<tools::Long>(_pFontSizeLB->get_value() / 10) );
+                nHeight = rOldItem.GetHeight()
+                          + o3tl::convert(_pFontSizeLB->get_value(), o3tl::Length::pt,
+                                          o3tl::Length::twip) / 10;
             else
                 nHeight = static_cast<tools::Long>(rOldItem.GetHeight() * _pFontSizeLB->get_value() / 100);
 
@@ -450,7 +453,8 @@ namespace
                 ItemToControl( nHeight, _pPage->GetItemSet().GetPool()->GetMetric( _nFontHeightWhich ), FieldUnit::TWIP ) );
         }
         else if ( !_pFontSizeLB->get_active_text().isEmpty() )
-            aSize.setHeight( PointToTwips( static_cast<tools::Long>(_pFontSizeLB->get_value() / 10) ) );
+            aSize.setHeight(o3tl::convert(_pFontSizeLB->get_value(), o3tl::Length::pt,
+                                          o3tl::Length::twip) / 10);
         else
             aSize.setHeight( 200 );   // default 10pt
         aFontMetrics.SetFontSize( aSize );
diff --git a/cui/source/tabpages/grfpage.cxx b/cui/source/tabpages/grfpage.cxx
index ddc47de404c2..569329e3a160 100644
--- a/cui/source/tabpages/grfpage.cxx
+++ b/cui/source/tabpages/grfpage.cxx
@@ -38,9 +38,9 @@
 #include <svtools/optionsdrawinglayer.hxx>
 #include <basegfx/matrix/b2dhommatrix.hxx>
 #include <basegfx/polygon/b2dpolygontools.hxx>
+#include <o3tl/unit_conversion.hxx>
 
-#define CM_1_TO_TWIP        567
-#define TWIP_TO_INCH        1440
+constexpr auto CM_1_TO_TWIP = o3tl::convert(1, o3tl::Length::cm, o3tl::Length::twip); // 567
 
 
 static int lcl_GetValue(const weld::MetricSpinButton& rMetric, FieldUnit eUnit)
@@ -646,16 +646,17 @@ void SvxGrfCropPage::GraphicHasChanged( bool bFound )
         }
 
         if ( aOrigPixelSize.Width() && aOrigPixelSize.Height() ) {
-             sal_Int32 ax = sal_Int32(floor(static_cast<float>(aOrigPixelSize.Width()) /
-                        (static_cast<float>(aOrigSize.Width())/TWIP_TO_INCH)+0.5));
-             sal_Int32 ay = sal_Int32(floor(static_cast<float>(aOrigPixelSize.Height()) /
-                        (static_cast<float>(aOrigSize.Height())/TWIP_TO_INCH)+0.5));
-             sTemp += " " + CuiResId( RID_SVXSTR_PPI );
+             sal_Int32 ax = 0.5 + aOrigPixelSize.Width() /
+                 o3tl::convert<double>(aOrigSize.Width(), o3tl::Length::twip,
+                                                          o3tl::Length::in);
+             sal_Int32 ay = 0.5 + aOrigPixelSize.Height() /
+                 o3tl::convert<double>(aOrigSize.Height(), o3tl::Length::twip,
+                                                           o3tl::Length::in);
              OUString sPPI = OUString::number(ax);
              if (abs(ax - ay) > 1) {
                 sPPI += u"\u00D7" + OUString::number(ay);
              }
-             sTemp = sTemp.replaceAll("%1", sPPI);
+             sTemp += " " + CuiResId(RID_SVXSTR_PPI).replaceAll("%1", sPPI);
         }
         m_xOrigSizeFT->set_label(sTemp);
     }
diff --git a/emfio/source/reader/wmfreader.cxx b/emfio/source/reader/wmfreader.cxx
index 78fee922ff35..999584b02294 100644
--- a/emfio/source/reader/wmfreader.cxx
+++ b/emfio/source/reader/wmfreader.cxx
@@ -24,6 +24,7 @@
 #include <memory>
 #include <optional>
 #include <o3tl/safeint.hxx>
+#include <o3tl/unit_conversion.hxx>
 #include <rtl/crc.h>
 #include <rtl/tencinfo.h>
 #include <sal/log.hxx>
@@ -1291,8 +1292,8 @@ namespace emfio
             {
                 // #n417818#: If we have an external header then overwrite the bounds!
                 tools::Rectangle aExtRect(0, 0,
-                    static_cast<double>(mpExternalHeader->xExt) * 567 * mnUnitsPerInch / 1440000,
-                    static_cast<double>(mpExternalHeader->yExt) * 567 * mnUnitsPerInch / 1440000);
+                    o3tl::convert(mpExternalHeader->xExt, o3tl::Length::mm100, o3tl::Length::px),
+                    o3tl::convert(mpExternalHeader->yExt, o3tl::Length::mm100, o3tl::Length::px));
                 aPlaceableBound = aExtRect;
 
                 SAL_INFO("vcl.wmf", "External header size "
diff --git a/include/o3tl/unit_conversion.hxx b/include/o3tl/unit_conversion.hxx
new file mode 100644
index 000000000000..17dd5ae12293
--- /dev/null
+++ b/include/o3tl/unit_conversion.hxx
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <o3tl/safeint.hxx>
+#include <sal/macros.h>
+#include <sal/types.h>
+
+#include <array>
+#include <cassert>
+#include <utility>
+#include <type_traits>
+
+namespace o3tl
+{
+// Length units
+enum class Length
+{
+    mm100 = 0, // 1/100th mm
+    mm10, // 1/10 mm, corresponds to MapUnit::Map10thMM
+    mm, // millimeter
+    cm, // centimeter
+    m, // meter
+    km, // kilometer
+    emu, // English Metric Unit: 1/360000 cm, 1/914400 in
+    twip, // "Twentieth of a point" aka "dxa": 1/20 pt
+    pt, // Point: 1/72 in
+    pc, // Pica: 1/6 in, corresponds to FieldUnit::PICA and MeasureUnit::PICA
+    in1000, // 1/1000 in, corresponds to MapUnit::Map1000thInch
+    in100, // 1/100 in, corresponds to MapUnit::Map100thInch
+    in10, // 1/10 in, corresponds to MapUnit::Map10thInch
+    in, // inch
+    ft, // foot
+    mi, // mile
+    master, // PPT Master Unit: 1/576 in
+    px, // "pixel" unit: 15 twip (96 ppi), corresponds to MeasureUnit::PIXEL
+    ch, // "char" unit: 210 twip (14 px), corresponds to FieldUnit::CHAR
+    line, // "line" unit: 312 twip, corresponds to FieldUnit::LINE
+    count, // <== add new units above this last entry
+    invalid = -1
+};
+
+// If other categories of units would be needed (like time), a separate scoped enum
+// should be created, respective conversion array prepared in detail namespace, and
+// respective md(NewUnit, NewUnit) overload introduced, which would allow using
+// o3tl::convert() and o3tl::convertSanitize() with the new category in a type-safe
+// way, without mixing unrelated units.
+
+namespace detail
+{
+// Common utilities
+
+// A special function to avoid compiler warning comparing signed and unsigned values
+template <typename I> constexpr bool isBetween(I n, sal_Int64 min, sal_Int64 max)
+{
+    assert(max > 0 && min < 0);
+    if constexpr (std::is_signed_v<I>)
+        return n >= min && n <= max;
+    else
+        return n <= sal_uInt64(max);
+}
+
+// Ensure correct rounding for both positive and negative integers
+template <typename I, std::enable_if_t<std::is_integral_v<I>, int> = 0>
+constexpr sal_Int64 MulDiv(I n, sal_Int64 m, sal_Int64 d)
+{
+    assert(m > 0 && d > 0);
+    assert(isBetween(n, (SAL_MIN_INT64 + d / 2) / m, (SAL_MAX_INT64 - d / 2) / m));
+    return (n >= 0 ? (n * m + d / 2) : (n * m - d / 2)) / d;
+}
+template <typename F, std::enable_if_t<std::is_floating_point_v<F>, int> = 0>
+constexpr double MulDiv(F f, sal_Int64 m, sal_Int64 d)
+{
+    assert(m > 0 && d > 0);
+    return f * (double(m) / d);
+}
+
+template <typename I, std::enable_if_t<std::is_integral_v<I>, int> = 0>
+constexpr sal_Int64 MulDiv(I n, sal_Int64 m, sal_Int64 d, bool& bOverflow, sal_Int64 nDefault)
+{
+    if (!isBetween(n, (SAL_MIN_INT64 + d / 2) / m, (SAL_MAX_INT64 - d / 2) / m))
+    {
+        bOverflow = true;
+        return nDefault;
+    }
+    bOverflow = false;
+    return MulDiv(n, m, d);
+}
+
+template <typename I, std::enable_if_t<std::is_integral_v<I>, int> = 0>
+constexpr sal_Int64 MulDivSaturate(I n, sal_Int64 m, sal_Int64 d)
+{
+    if (!isBetween(n, (SAL_MIN_INT64 + d / 2) / m, (SAL_MAX_INT64 - d / 2) / m))
+    {
+        if (m > d && !isBetween(n, SAL_MIN_INT64 / m * d + d / 2, SAL_MAX_INT64 / m * d - d / 2))
+            return n > 0 ? SAL_MAX_INT64 : SAL_MIN_INT64; // saturate
+        return (n >= 0 ? n + d / 2 : n - d / 2) / d * m; // divide before multiplication
+    }
+    return MulDiv(n, m, d);
+}
+
+// Greatest common divisor
+constexpr int gcd(sal_Int64 a, sal_Int64 b) { return b == 0 ? a : gcd(b, a % b); }
+
+// Packs integral multiplier and divisor for conversion from one unit to another
+struct m_and_d
+{
+    sal_Int64 m; // multiplier
+    sal_Int64 d; // divisor
+    constexpr m_and_d(sal_Int64 _m, sal_Int64 _d)
+        : m(_m / gcd(_m, _d)) // make sure to use smallest quotients here because
+        , d(_d / gcd(_m, _d)) // they will be multiplied when building final table
+    {
+        assert(_m > 0 && _d > 0);
+    }
+};
+
+// Resulting static array N x N of all quotients to convert between all units. The
+// quotients are minimal to allow largest range of converted numbers without overflow.
+// Maybe o3tl::enumarray could be used here, but it's not constexpr yet.
+template <int N> constexpr auto prepareMDArray(const m_and_d (&mdBase)[N])
+{
+    std::array<std::array<sal_Int64, N>, N> a{};
+    for (int i = 0; i < N; ++i)
+    {
+        for (int j = 0; j <= i; ++j)
+        {
+            if (i == j)
+                a[i][j] = 1;
+            else
+            {
+                assert(mdBase[i].m < SAL_MAX_INT64 / mdBase[j].d);
+                assert(mdBase[i].d < SAL_MAX_INT64 / mdBase[j].m);
+                const sal_Int64 m = mdBase[i].m * mdBase[j].d, d = mdBase[i].d * mdBase[j].m;
+                const sal_Int64 g = gcd(m, d);
+                a[i][j] = m / g;
+                a[j][i] = d / g;
+            }
+        }
+    }
+    return a;
+}
+
+// Length units implementation
+
+// Array of conversion quotients for mm, used to build final conversion table. Entries
+// are { multiplier, divider } to convert respective unit *to* mm. Order of elements
+// corresponds to order in o3tl::Length enum (Length::count and Length::invalid omitted).
+constexpr m_and_d mdBaseLen[] = {
+    { 1, 100 }, // mm100 => mm
+    { 1, 10 }, // mm10 => mm
+    { 1, 1 }, // mm => mm
+    { 10, 1 }, // cm => mm
+    { 1000, 1 }, // m => mm
+    { 1000000, 1 }, // km => mm
+    { 1, 36000 }, // emu => mm
+    { 254, 10 * 1440 }, // twip => mm
+    { 254, 10 * 72 }, // pt => mm
+    { 254, 10 * 6 }, // pc => mm
+    { 254, 10000 }, // in1000 => mm
+    { 254, 1000 }, // in100 => mm
+    { 254, 100 }, // in10 => mm
+    { 254, 10 }, // in => mm
+    { 254 * 12, 10 }, // ft => mm
+    { 254 * 12 * 5280, 10 }, // mi => mm
+    { 254, 10 * 576 }, // master => mm
+    { 254 * 15, 10 * 1440 }, // px => mm
+    { 254 * 210, 10 * 1440 }, // ch => mm
+    { 254 * 312, 10 * 1440 }, // line => mm
+};
+static_assert(SAL_N_ELEMENTS(mdBaseLen) == static_cast<int>(Length::count),
+              "mdBaseL must have an entry for each unit in o3tl::Length");
+
+// an overload taking Length
+constexpr sal_Int64 md(Length i, Length j)
+{
+    // The resulting multipliers and divisors array
+    constexpr auto aMDArray = prepareMDArray(mdBaseLen);
+
+    const int nI = static_cast<int>(i), nJ = static_cast<int>(j);
+    assert(nI >= 0 && o3tl::make_unsigned(nI) < aMDArray.size());
+    assert(nJ >= 0 && o3tl::make_unsigned(nJ) < aMDArray.size());
+    return aMDArray[nI][nJ];
+}
+
+// here might go overloads of md() taking other units ...
+}
+
+// Unchecked conversion. Takes a number value, multiplier and divisor
+template <typename N> constexpr auto convert(N n, sal_Int64 mul, sal_Int64 div)
+{
+    return detail::MulDiv(n, mul, div);
+}
+
+// Unchecked conversion. Takes a number value and units defined in this header
+template <typename N, typename U> constexpr auto convert(N n, U from, U to)
+{
+    return convert(n, detail::md(from, to), detail::md(to, from));
+}
+
+// Returns nDefault if intermediate multiplication overflows sal_Int64 (only for integral types).
+// On return, bOverflow indicates if overflow happened.
+template <typename N, typename U>
+constexpr auto convert(N n, U from, U to, bool& bOverflow, sal_Int64 nDefault = 0)
+{
+    return detail::MulDiv(n, detail::md(from, to), detail::md(to, from), bOverflow, nDefault);
+}
+
+// Conversion with saturation (only for integral types). For too large input returns SAL_MAX_INT64.
+// When intermediate multiplication would overflow, but otherwise result in in sal_Int64 range, the
+// precision is decreased because of inversion of multiplication and division.
+template <typename N, typename U> constexpr auto convertSaturate(N n, U from, U to)
+{
+    return detail::MulDivSaturate(n, detail::md(from, to), detail::md(to, from));
+}
+
+// Return a pair { multiplier, divisor } for a given conversion
+template <typename U> constexpr std::pair<sal_Int64, sal_Int64> getConversionMulDiv(U from, U to)
+{
+    return { detail::md(from, to), detail::md(to, from) };
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/include/oox/drawingml/drawingmltypes.hxx b/include/oox/drawingml/drawingmltypes.hxx
index b8693c00fdeb..c24bff255a3e 100644
--- a/include/oox/drawingml/drawingmltypes.hxx
+++ b/include/oox/drawingml/drawingmltypes.hxx
@@ -31,6 +31,7 @@
 #include <com/sun/star/style/TabAlign.hpp>
 #include <com/sun/star/uno/Reference.hxx>
 #include <o3tl/safeint.hxx>
+#include <o3tl/unit_conversion.hxx>
 #include <oox/dllapi.h>
 #include <oox/helper/helper.hxx>
 #include <rtl/ustring.hxx>
@@ -171,33 +172,30 @@ inline OString calcRotationValue(sal_Int32 nRotation)
     return OString::number(nRotation);
 }
 
-const sal_Int32 EMU_PER_HMM = 360;      /// 360 EMUs per 1/100 mm.
-const sal_Int32 EMU_PER_PT = 12700;
-
 /** Converts the passed 32-bit integer value from 1/100 mm to EMUs. */
 inline sal_Int64 convertHmmToEmu( sal_Int32 nValue )
 {
-    return static_cast< sal_Int64 >( nValue ) * EMU_PER_HMM;
+    return o3tl::convert(nValue, o3tl::Length::mm100, o3tl::Length::emu);
 }
 
 /** Converts the passed 64-bit integer value from EMUs to 1/100 mm. */
 inline sal_Int32 convertEmuToHmm( sal_Int64 nValue )
 {
-    sal_Int32 nCorrection = (nValue > 0 ? 1 : -1) * EMU_PER_HMM / 2; // So that the implicit floor will round.
-    return getLimitedValue<sal_Int32, sal_Int64>(o3tl::saturating_add<sal_Int64>(nValue, nCorrection) / EMU_PER_HMM, SAL_MIN_INT32, SAL_MAX_INT32);
+    return getLimitedValue<sal_Int32, sal_Int64>(
+        o3tl::convert(nValue, o3tl::Length::emu, o3tl::Length::mm100), SAL_MIN_INT32,
+        SAL_MAX_INT32);
 }
 
 /** Converts the passed 64-bit integer value from EMUs to Points. */
 inline float convertEmuToPoints( sal_Int64 nValue )
 {
-    return static_cast<float>(nValue) / EMU_PER_PT;
+    return o3tl::convert<double>(nValue, o3tl::Length::emu, o3tl::Length::pt);
 }
 
 /** Converts the passed double value from points to mm. */
 inline double convertPointToMms(double fValue)
 {
-    constexpr double fFactor = static_cast<double>(EMU_PER_PT) / (EMU_PER_HMM * 100);
-    return fValue * fFactor;
+    return o3tl::convert(fValue, o3tl::Length::pt, o3tl::Length::mm);
 }
 
 /** A structure for a point with 64-bit integer components. */
diff --git a/include/svtools/unitconv.hxx b/include/svtools/unitconv.hxx
index 34025261e46c..88bbffc146e5 100644
--- a/include/svtools/unitconv.hxx
+++ b/include/svtools/unitconv.hxx
@@ -46,8 +46,6 @@ SVT_DLLPUBLIC FieldUnit MapToFieldUnit( const MapUnit eUnit );
 SVT_DLLPUBLIC void      SetMetricValue(weld::MetricSpinButton& rField, int lCoreValue, MapUnit eUnit);
 SVT_DLLPUBLIC int       GetCoreValue(const weld::MetricSpinButton& rField, MapUnit eUnit);
 
-SVT_DLLPUBLIC tools::Long  PointToTwips( tools::Long nIn );
-
 SVT_DLLPUBLIC tools::Long  TransformMetric( tools::Long nVal, FieldUnit aOld, FieldUnit aNew );
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/tools/UnitConversion.hxx b/include/tools/UnitConversion.hxx
index 802a372a546d..7d3bdf565c1d 100644
--- a/include/tools/UnitConversion.hxx
+++ b/include/tools/UnitConversion.hxx
@@ -10,61 +10,117 @@
 
 #pragma once
 
+#include <o3tl/unit_conversion.hxx>
 #include <sal/types.h>
-#include <cassert>
-#include <type_traits>
+#include <tools/fldunit.hxx>
+#include <tools/fract.hxx>
+#include <tools/mapunit.hxx>
 
-template <typename I> constexpr bool isBetween(I n, sal_Int64 min, sal_Int64 max)
+constexpr o3tl::Length FieldToO3tlLength(FieldUnit eU, o3tl::Length ePixelValue = o3tl::Length::px)
 {
-    assert(max > 0 && min < 0);
-    if constexpr (std::is_signed_v<I>)
-        return n >= min && n <= max;
-    else
-        return n <= sal_uInt64(max);
+    switch (eU)
+    {
+        case FieldUnit::MM:
+            return o3tl::Length::mm;
+        case FieldUnit::CM:
+            return o3tl::Length::cm;
+        case FieldUnit::M:
+            return o3tl::Length::m;
+        case FieldUnit::KM:
+            return o3tl::Length::km;
+        case FieldUnit::TWIP:
+            return o3tl::Length::twip;
+        case FieldUnit::POINT:
+            return o3tl::Length::pt;
+        case FieldUnit::PICA:
+            return o3tl::Length::pc;
+        case FieldUnit::INCH:
+            return o3tl::Length::in;
+        case FieldUnit::FOOT:
+            return o3tl::Length::ft;
+        case FieldUnit::MILE:
+            return o3tl::Length::mi;
+        case FieldUnit::CHAR:
+            return o3tl::Length::ch;
+        case FieldUnit::LINE:
+            return o3tl::Length::line;
+        case FieldUnit::MM_100TH:
+            return o3tl::Length::mm100;
+        case FieldUnit::PIXEL:
+            return ePixelValue;
+        default:
+            return o3tl::Length::invalid;
+    }
 }
 
-constexpr int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
-
-// Ensure correct rounding for both positive and negative integers
-template <int mul, int div, typename I, std::enable_if_t<std::is_integral_v<I>, int> = 0>
-constexpr sal_Int64 MulDiv(I n)
+constexpr o3tl::Length MapToO3tlLength(MapUnit eU, o3tl::Length ePixelValue = o3tl::Length::px)
 {
-    static_assert(mul > 0 && div > 0);
-    constexpr int m = mul / gcd(mul, div), d = div / gcd(mul, div);
-    assert(isBetween(n, (SAL_MIN_INT64 + d / 2) / m, (SAL_MAX_INT64 - d / 2) / m));
-    return (n >= 0 ? (sal_Int64(n) * m + d / 2) : (sal_Int64(n) * m - d / 2)) / d;
+    switch (eU)
+    {
+        case MapUnit::Map100thMM:
+            return o3tl::Length::mm100;
+        case MapUnit::Map10thMM:
+            return o3tl::Length::mm10;
+        case MapUnit::MapMM:
+            return o3tl::Length::mm;
+        case MapUnit::MapCM:
+            return o3tl::Length::cm;
+        case MapUnit::Map1000thInch:
+            return o3tl::Length::in1000;
+        case MapUnit::Map100thInch:
+            return o3tl::Length::in100;
+        case MapUnit::Map10thInch:
+            return o3tl::Length::in10;
+        case MapUnit::MapInch:
+            return o3tl::Length::in;
+        case MapUnit::MapPoint:
+            return o3tl::Length::pt;
+        case MapUnit::MapTwip:
+            return o3tl::Length::twip;
+        case MapUnit::MapPixel:
+            return ePixelValue;
+        default:
+            return o3tl::Length::invalid;
+    }
 }
-template <int mul, int div, typename F, std::enable_if_t<std::is_floating_point_v<F>, int> = 0>
-constexpr double MulDiv(F f)
+
+inline Fraction conversionFract(o3tl::Length from, o3tl::Length to)
 {
-    static_assert(mul > 0 && div > 0);
-    return f * (double(mul) / div);
+    const auto & [ mul, div ] = o3tl::getConversionMulDiv(from, to);
+    return { mul, div };
 }
 
-template <int mul, int div, typename I, std::enable_if_t<std::is_integral_v<I>, int> = 0>
-constexpr sal_Int64 sanitizeMulDiv(I n)
+template <typename N> constexpr auto convertTwipToMm100(N n)
 {
-    constexpr int m = mul / gcd(mul, div), d = div / gcd(mul, div);
-    if constexpr (m > d)
-        if (!isBetween(n, SAL_MIN_INT64 / m * d + d / 2, SAL_MAX_INT64 / m * d - d / 2))
-            return n > 0 ? SAL_MAX_INT64 : SAL_MIN_INT64; // saturate
-    if (!isBetween(n, (SAL_MIN_INT64 + d / 2) / m, (SAL_MAX_INT64 - d / 2) / m))
-        return (n >= 0 ? n + d / 2 : n - d / 2) / d * m; // divide before multiplication
-    return MulDiv<mul, div>(n);
+    return o3tl::convert(n, o3tl::Length::twip, o3tl::Length::mm100);
+}
+template <typename N> constexpr auto convertMm100ToTwip(N n)
+{
+    return o3tl::convert(n, o3tl::Length::mm100, o3tl::Length::twip);
 }
 
-template <typename N> constexpr auto convertTwipToMm100(N n) { return MulDiv<127, 72>(n); }
-template <typename N> constexpr auto convertMm100ToTwip(N n) { return MulDiv<72, 127>(n); }
-
-constexpr sal_Int64 sanitiseMm100ToTwip(sal_Int64 n) { return sanitizeMulDiv<72, 127>(n); }
-
-template <typename N> constexpr auto convertPointToTwip(N n) { return MulDiv<20, 1>(n); }
+constexpr sal_Int64 sanitiseMm100ToTwip(sal_Int64 n)
+{
+    return o3tl::convertSaturate(n, o3tl::Length::mm100, o3tl::Length::twip);
+}
 
-template <typename N> constexpr auto convertPointToMm100(N n) { return MulDiv<2540, 72>(n); }
-template <typename N> constexpr auto convertMm100ToPoint(N n) { return MulDiv<72, 2540>(n); }
+template <typename N> constexpr auto convertPointToMm100(N n)
+{
+    return o3tl::convert(n, o3tl::Length::pt, o3tl::Length::mm100);
+}
+template <typename N> constexpr auto convertMm100ToPoint(N n)
+{
+    return o3tl::convert(n, o3tl::Length::mm100, o3tl::Length::pt);
+}
 
 // PPT's "master unit" (1/576 inch) <=> mm/100
-template <typename N> constexpr auto convertMasterUnitToMm100(N n) { return MulDiv<2540, 576>(n); }
-template <typename N> constexpr auto convertMm100ToMasterUnit(N n) { return MulDiv<576, 2540>(n); }
+template <typename N> constexpr auto convertMasterUnitToMm100(N n)
+{
+    return o3tl::convert(n, o3tl::Length::master, o3tl::Length::mm100);
+}
+template <typename N> constexpr auto convertMm100ToMasterUnit(N n)
+{
+    return o3tl::convert(n, o3tl::Length::mm100, o3tl::Length::master);
+}
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/o3tl/CppunitTest_o3tl_tests.mk b/o3tl/CppunitTest_o3tl_tests.mk
index 07229a9384b1..6866778f6c1a 100644
--- a/o3tl/CppunitTest_o3tl_tests.mk
+++ b/o3tl/CppunitTest_o3tl_tests.mk
@@ -35,6 +35,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,o3tl_tests,\
 	o3tl/qa/test-span \
 	o3tl/qa/test-temporary \
 	o3tl/qa/test-typed_flags \
+	o3tl/qa/test-unit_conversion \
 	o3tl/qa/test-vector_pool \
 ))
 
diff --git a/o3tl/qa/test-unit_conversion.cxx b/o3tl/qa/test-unit_conversion.cxx
new file mode 100644
index 000000000000..72a0e9b1f43c
--- /dev/null
+++ b/o3tl/qa/test-unit_conversion.cxx
@@ -0,0 +1,872 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/unit_conversion.hxx>
+
+// Just some static asserts
+
+namespace
+{
+constexpr double const_abs(double f) { return f >= 0 ? f : -f; }
+constexpr bool eq(double a, double b) { return const_abs(a - b) < 1E-6; }
+bool eq(sal_Int64, double) = delete;
+}
+
+// testing floating-point conversion
+
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm100, o3tl::Length::mm100), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm10, o3tl::Length::mm100), 10));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm, o3tl::Length::mm100), 100));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::cm, o3tl::Length::mm100), 1000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::m, o3tl::Length::mm100), 100000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::mm100), 100E6));
+static_assert(eq(o3tl::convert(360.0, o3tl::Length::emu, o3tl::Length::mm100), 1));
+static_assert(eq(o3tl::convert(72.0, o3tl::Length::twip, o3tl::Length::mm100), 127));
+static_assert(eq(o3tl::convert(18.0, o3tl::Length::pt, o3tl::Length::mm100), 635));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::pc, o3tl::Length::mm100), 1270));
+static_assert(eq(o3tl::convert(50.0, o3tl::Length::in1000, o3tl::Length::mm100), 127));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in100, o3tl::Length::mm100), 127));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in10, o3tl::Length::mm100), 254));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::mm100), 2540));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::mm100), 30480));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::mm100), 160934400));
+static_assert(eq(o3tl::convert(144.0, o3tl::Length::master, o3tl::Length::mm100), 635));
+static_assert(eq(o3tl::convert(24.0, o3tl::Length::px, o3tl::Length::mm100), 635));
+static_assert(eq(o3tl::convert(12.0, o3tl::Length::ch, o3tl::Length::mm100), 4445));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::line, o3tl::Length::mm100), 1651));
+
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::mm100, o3tl::Length::mm10), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm10, o3tl::Length::mm10), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm, o3tl::Length::mm10), 10));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::cm, o3tl::Length::mm10), 100));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::m, o3tl::Length::mm10), 10000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::mm10), 10E6));
+static_assert(eq(o3tl::convert(3600.0, o3tl::Length::emu, o3tl::Length::mm10), 1));
+static_assert(eq(o3tl::convert(720.0, o3tl::Length::twip, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(36.0, o3tl::Length::pt, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::pc, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(500.0, o3tl::Length::in1000, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(50.0, o3tl::Length::in100, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in10, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::mm10), 254));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::mm10), 3048));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::mm10), 16093440));
+static_assert(eq(o3tl::convert(288.0, o3tl::Length::master, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(48.0, o3tl::Length::px, o3tl::Length::mm10), 127));
+static_assert(eq(o3tl::convert(24.0, o3tl::Length::ch, o3tl::Length::mm10), 889));
+static_assert(eq(o3tl::convert(30.0, o3tl::Length::line, o3tl::Length::mm10), 1651));
+
+static_assert(eq(o3tl::convert(100.0, o3tl::Length::mm100, o3tl::Length::mm), 1));
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::mm10, o3tl::Length::mm), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm, o3tl::Length::mm), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::cm, o3tl::Length::mm), 10));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::m, o3tl::Length::mm), 1000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::mm), 1E6));
+static_assert(eq(o3tl::convert(36000.0, o3tl::Length::emu, o3tl::Length::mm), 1));
+static_assert(eq(o3tl::convert(7200.0, o3tl::Length::twip, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(360.0, o3tl::Length::pt, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(30.0, o3tl::Length::pc, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(5000.0, o3tl::Length::in1000, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(500.0, o3tl::Length::in100, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(50.0, o3tl::Length::in10, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::ft, o3tl::Length::mm), 1524));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::mm), 1609344));
+static_assert(eq(o3tl::convert(2880.0, o3tl::Length::master, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(480.0, o3tl::Length::px, o3tl::Length::mm), 127));
+static_assert(eq(o3tl::convert(240.0, o3tl::Length::ch, o3tl::Length::mm), 889));
+static_assert(eq(o3tl::convert(300.0, o3tl::Length::line, o3tl::Length::mm), 1651));
+
+static_assert(eq(o3tl::convert(1000.0, o3tl::Length::mm100, o3tl::Length::cm), 1));
+static_assert(eq(o3tl::convert(100.0, o3tl::Length::mm10, o3tl::Length::cm), 1));
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::mm, o3tl::Length::cm), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::cm, o3tl::Length::cm), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::m, o3tl::Length::cm), 100));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::cm), 100000));
+static_assert(eq(o3tl::convert(360000.0, o3tl::Length::emu, o3tl::Length::cm), 1));
+static_assert(eq(o3tl::convert(72000.0, o3tl::Length::twip, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(3600.0, o3tl::Length::pt, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(300.0, o3tl::Length::pc, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(50000.0, o3tl::Length::in1000, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(5000.0, o3tl::Length::in100, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(500.0, o3tl::Length::in10, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(50.0, o3tl::Length::in, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(25.0, o3tl::Length::ft, o3tl::Length::cm), 762));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::mi, o3tl::Length::cm), 804672));
+static_assert(eq(o3tl::convert(28800.0, o3tl::Length::master, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(4800.0, o3tl::Length::px, o3tl::Length::cm), 127));
+static_assert(eq(o3tl::convert(2400.0, o3tl::Length::ch, o3tl::Length::cm), 889));
+static_assert(eq(o3tl::convert(3000.0, o3tl::Length::line, o3tl::Length::cm), 1651));
+
+static_assert(eq(o3tl::convert(100000.0, o3tl::Length::mm100, o3tl::Length::m), 1));
+static_assert(eq(o3tl::convert(10000.0, o3tl::Length::mm10, o3tl::Length::m), 1));
+static_assert(eq(o3tl::convert(1000.0, o3tl::Length::mm, o3tl::Length::m), 1));
+static_assert(eq(o3tl::convert(100.0, o3tl::Length::cm, o3tl::Length::m), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::m, o3tl::Length::m), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::m), 1000));
+static_assert(eq(o3tl::convert(36E6, o3tl::Length::emu, o3tl::Length::m), 1));
+static_assert(eq(o3tl::convert(7200000.0, o3tl::Length::twip, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(360000.0, o3tl::Length::pt, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(30000.0, o3tl::Length::pc, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(5000000.0, o3tl::Length::in1000, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(500000.0, o3tl::Length::in100, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(50000.0, o3tl::Length::in10, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(5000.0, o3tl::Length::in, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(1250.0, o3tl::Length::ft, o3tl::Length::m), 381));
+static_assert(eq(o3tl::convert(125.0, o3tl::Length::mi, o3tl::Length::m), 201168));
+static_assert(eq(o3tl::convert(2880000.0, o3tl::Length::master, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(480000.0, o3tl::Length::px, o3tl::Length::m), 127));
+static_assert(eq(o3tl::convert(240000.0, o3tl::Length::ch, o3tl::Length::m), 889));
+static_assert(eq(o3tl::convert(300000.0, o3tl::Length::line, o3tl::Length::m), 1651));
+
+static_assert(eq(o3tl::convert(100E6, o3tl::Length::mm100, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(10E6, o3tl::Length::mm10, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(1E6, o3tl::Length::mm, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(100000.0, o3tl::Length::cm, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(1000.0, o3tl::Length::m, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(36E9, o3tl::Length::emu, o3tl::Length::km), 1));
+static_assert(eq(o3tl::convert(7200E6, o3tl::Length::twip, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(360E6, o3tl::Length::pt, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(30E6, o3tl::Length::pc, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(5E9, o3tl::Length::in1000, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(500E6, o3tl::Length::in100, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(50E6, o3tl::Length::in10, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(5E6, o3tl::Length::in, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(1250000.0, o3tl::Length::ft, o3tl::Length::km), 381));
+static_assert(eq(o3tl::convert(15625.0, o3tl::Length::mi, o3tl::Length::km), 25146));
+static_assert(eq(o3tl::convert(2880E6, o3tl::Length::master, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(480E6, o3tl::Length::px, o3tl::Length::km), 127));
+static_assert(eq(o3tl::convert(240E6, o3tl::Length::ch, o3tl::Length::km), 889));
+static_assert(eq(o3tl::convert(300E6, o3tl::Length::line, o3tl::Length::km), 1651));
+
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm100, o3tl::Length::emu), 360));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm10, o3tl::Length::emu), 3600));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mm, o3tl::Length::emu), 36000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::cm, o3tl::Length::emu), 360000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::m, o3tl::Length::emu), 36E6));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::km, o3tl::Length::emu), 36E9));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::emu, o3tl::Length::emu), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::emu), 635));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pt, o3tl::Length::emu), 12700));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pc, o3tl::Length::emu), 152400));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in1000, o3tl::Length::emu), 4572));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in100, o3tl::Length::emu), 9144));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in10, o3tl::Length::emu), 91440));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::emu), 914400));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::emu), 10972800));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::emu), 57936384000));
+static_assert(eq(o3tl::convert(2.0, o3tl::Length::master, o3tl::Length::emu), 3175));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::px, o3tl::Length::emu), 9525));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ch, o3tl::Length::emu), 133350));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::line, o3tl::Length::emu), 198120));
+
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm100, o3tl::Length::twip), 72));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::twip), 720));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::twip), 7200));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::twip), 72000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::twip), 7200000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::twip), 7200E6));
+static_assert(eq(o3tl::convert(635.0, o3tl::Length::emu, o3tl::Length::twip), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::twip), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pt, o3tl::Length::twip), 20));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pc, o3tl::Length::twip), 240));
+static_assert(eq(o3tl::convert(25.0, o3tl::Length::in1000, o3tl::Length::twip), 36));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in100, o3tl::Length::twip), 72));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in10, o3tl::Length::twip), 144));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::twip), 1440));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::twip), 17280));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::twip), 91238400));
+static_assert(eq(o3tl::convert(2.0, o3tl::Length::master, o3tl::Length::twip), 5));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::px, o3tl::Length::twip), 15));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ch, o3tl::Length::twip), 210));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::line, o3tl::Length::twip), 312));
+
+static_assert(eq(o3tl::convert(635.0, o3tl::Length::mm100, o3tl::Length::pt), 18));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::pt), 36));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::pt), 360));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::pt), 3600));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::pt), 360000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::pt), 360E6));
+static_assert(eq(o3tl::convert(12700.0, o3tl::Length::emu, o3tl::Length::pt), 1));
+static_assert(eq(o3tl::convert(20.0, o3tl::Length::twip, o3tl::Length::pt), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pt, o3tl::Length::pt), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pc, o3tl::Length::pt), 12));
+static_assert(eq(o3tl::convert(125.0, o3tl::Length::in1000, o3tl::Length::pt), 9));
+static_assert(eq(o3tl::convert(25.0, o3tl::Length::in100, o3tl::Length::pt), 18));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in10, o3tl::Length::pt), 36));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::pt), 72));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::pt), 864));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::pt), 4561920));
+static_assert(eq(o3tl::convert(8.0, o3tl::Length::master, o3tl::Length::pt), 1));
+static_assert(eq(o3tl::convert(4.0, o3tl::Length::px, o3tl::Length::pt), 3));
+static_assert(eq(o3tl::convert(2.0, o3tl::Length::ch, o3tl::Length::pt), 21));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::line, o3tl::Length::pt), 78));
+
+static_assert(eq(o3tl::convert(1270.0, o3tl::Length::mm100, o3tl::Length::pc), 3));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::pc), 3));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::pc), 30));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::pc), 300));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::pc), 30000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::pc), 30E6));
+static_assert(eq(o3tl::convert(152400.0, o3tl::Length::emu, o3tl::Length::pc), 1));
+static_assert(eq(o3tl::convert(240.0, o3tl::Length::twip, o3tl::Length::pc), 1));
+static_assert(eq(o3tl::convert(12.0, o3tl::Length::pt, o3tl::Length::pc), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pc, o3tl::Length::pc), 1));
+static_assert(eq(o3tl::convert(500.0, o3tl::Length::in1000, o3tl::Length::pc), 3));
+static_assert(eq(o3tl::convert(50.0, o3tl::Length::in100, o3tl::Length::pc), 3));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in10, o3tl::Length::pc), 3));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::pc), 6));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::pc), 72));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::pc), 380160));
+static_assert(eq(o3tl::convert(96.0, o3tl::Length::master, o3tl::Length::pc), 1));
+static_assert(eq(o3tl::convert(16.0, o3tl::Length::px, o3tl::Length::pc), 1));
+static_assert(eq(o3tl::convert(8.0, o3tl::Length::ch, o3tl::Length::pc), 7));
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::line, o3tl::Length::pc), 13));
+
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm100, o3tl::Length::in1000), 50));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::in1000), 500));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::in1000), 5000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::in1000), 50000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::in1000), 5E6));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::in1000), 5E9));
+static_assert(eq(o3tl::convert(4572.0, o3tl::Length::emu, o3tl::Length::in1000), 5));
+static_assert(eq(o3tl::convert(36.0, o3tl::Length::twip, o3tl::Length::in1000), 25));
+static_assert(eq(o3tl::convert(9.0, o3tl::Length::pt, o3tl::Length::in1000), 125));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::pc, o3tl::Length::in1000), 500));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in1000, o3tl::Length::in1000), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in100, o3tl::Length::in1000), 10));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in10, o3tl::Length::in1000), 100));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::in1000), 1000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::in1000), 12000));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::in1000), 63360000));
+static_assert(eq(o3tl::convert(72.0, o3tl::Length::master, o3tl::Length::in1000), 125));
+static_assert(eq(o3tl::convert(12.0, o3tl::Length::px, o3tl::Length::in1000), 125));
+static_assert(eq(o3tl::convert(6.0, o3tl::Length::ch, o3tl::Length::in1000), 875));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::line, o3tl::Length::in1000), 650));
+
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm100, o3tl::Length::in100), 5));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::in100), 50));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::in100), 500));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::in100), 5000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::in100), 500000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::in100), 500E6));
+static_assert(eq(o3tl::convert(9144.0, o3tl::Length::emu, o3tl::Length::in100), 1));
+static_assert(eq(o3tl::convert(72.0, o3tl::Length::twip, o3tl::Length::in100), 5));
+static_assert(eq(o3tl::convert(18.0, o3tl::Length::pt, o3tl::Length::in100), 25));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::pc, o3tl::Length::in100), 50));
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::in1000, o3tl::Length::in100), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in100, o3tl::Length::in100), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in10, o3tl::Length::in100), 10));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::in100), 100));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::in100), 1200));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::in100), 6336000));
+static_assert(eq(o3tl::convert(144.0, o3tl::Length::master, o3tl::Length::in100), 25));
+static_assert(eq(o3tl::convert(24.0, o3tl::Length::px, o3tl::Length::in100), 25));
+static_assert(eq(o3tl::convert(12.0, o3tl::Length::ch, o3tl::Length::in100), 175));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::line, o3tl::Length::in100), 65));
+
+static_assert(eq(o3tl::convert(254.0, o3tl::Length::mm100, o3tl::Length::in10), 1));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::in10), 5));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::in10), 50));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::in10), 500));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::in10), 50000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::in10), 50E6));
+static_assert(eq(o3tl::convert(91440.0, o3tl::Length::emu, o3tl::Length::in10), 1));
+static_assert(eq(o3tl::convert(144.0, o3tl::Length::twip, o3tl::Length::in10), 1));
+static_assert(eq(o3tl::convert(36.0, o3tl::Length::pt, o3tl::Length::in10), 5));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::pc, o3tl::Length::in10), 5));
+static_assert(eq(o3tl::convert(100.0, o3tl::Length::in1000, o3tl::Length::in10), 1));
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::in100, o3tl::Length::in10), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in10, o3tl::Length::in10), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::in10), 10));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::in10), 120));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::in10), 633600));
+static_assert(eq(o3tl::convert(288.0, o3tl::Length::master, o3tl::Length::in10), 5));
+static_assert(eq(o3tl::convert(48.0, o3tl::Length::px, o3tl::Length::in10), 5));
+static_assert(eq(o3tl::convert(24.0, o3tl::Length::ch, o3tl::Length::in10), 35));
+static_assert(eq(o3tl::convert(6.0, o3tl::Length::line, o3tl::Length::in10), 13));
+
+static_assert(eq(o3tl::convert(2540.0, o3tl::Length::mm100, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(254.0, o3tl::Length::mm10, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::in), 5));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::in), 50));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::in), 5000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::in), 5E6));
+static_assert(eq(o3tl::convert(914400.0, o3tl::Length::emu, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(1440.0, o3tl::Length::twip, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(72.0, o3tl::Length::pt, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(6.0, o3tl::Length::pc, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(1000.0, o3tl::Length::in1000, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(100.0, o3tl::Length::in100, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(10.0, o3tl::Length::in10, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::in), 12));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::in), 63360));
+static_assert(eq(o3tl::convert(576.0, o3tl::Length::master, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(96.0, o3tl::Length::px, o3tl::Length::in), 1));
+static_assert(eq(o3tl::convert(48.0, o3tl::Length::ch, o3tl::Length::in), 7));
+static_assert(eq(o3tl::convert(60.0, o3tl::Length::line, o3tl::Length::in), 13));
+
+static_assert(eq(o3tl::convert(30480.0, o3tl::Length::mm100, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(3048.0, o3tl::Length::mm10, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(1524.0, o3tl::Length::mm, o3tl::Length::ft), 5));
+static_assert(eq(o3tl::convert(762.0, o3tl::Length::cm, o3tl::Length::ft), 25));
+static_assert(eq(o3tl::convert(381.0, o3tl::Length::m, o3tl::Length::ft), 1250));
+static_assert(eq(o3tl::convert(381.0, o3tl::Length::km, o3tl::Length::ft), 1250000));
+static_assert(eq(o3tl::convert(10972800.0, o3tl::Length::emu, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(17280.0, o3tl::Length::twip, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(864.0, o3tl::Length::pt, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(72.0, o3tl::Length::pc, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(12000.0, o3tl::Length::in1000, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(1200.0, o3tl::Length::in100, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(120.0, o3tl::Length::in10, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(12.0, o3tl::Length::in, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::ft), 5280));
+static_assert(eq(o3tl::convert(6912.0, o3tl::Length::master, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(1152.0, o3tl::Length::px, o3tl::Length::ft), 1));
+static_assert(eq(o3tl::convert(576.0, o3tl::Length::ch, o3tl::Length::ft), 7));
+static_assert(eq(o3tl::convert(720.0, o3tl::Length::line, o3tl::Length::ft), 13));
+
+static_assert(eq(o3tl::convert(160934400.0, o3tl::Length::mm100, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(16093440.0, o3tl::Length::mm10, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(1609344.0, o3tl::Length::mm, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(804672.0, o3tl::Length::cm, o3tl::Length::mi), 5));
+static_assert(eq(o3tl::convert(201168.0, o3tl::Length::m, o3tl::Length::mi), 125));
+static_assert(eq(o3tl::convert(25146.0, o3tl::Length::km, o3tl::Length::mi), 15625));
+static_assert(eq(o3tl::convert(57936384000.0, o3tl::Length::emu, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(91238400.0, o3tl::Length::twip, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(4561920.0, o3tl::Length::pt, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(380160.0, o3tl::Length::pc, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(63360000.0, o3tl::Length::in1000, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(6336000.0, o3tl::Length::in100, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(633600.0, o3tl::Length::in10, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(63360.0, o3tl::Length::in, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(5280.0, o3tl::Length::ft, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(36495360.0, o3tl::Length::master, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(6082560.0, o3tl::Length::px, o3tl::Length::mi), 1));
+static_assert(eq(o3tl::convert(3041280.0, o3tl::Length::ch, o3tl::Length::mi), 7));
+static_assert(eq(o3tl::convert(3801600.0, o3tl::Length::line, o3tl::Length::mi), 13));
+
+static_assert(eq(o3tl::convert(635.0, o3tl::Length::mm100, o3tl::Length::master), 144));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::master), 288));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::master), 2880));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::master), 28800));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::master), 2880000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::master), 2880E6));
+static_assert(eq(o3tl::convert(3175.0, o3tl::Length::emu, o3tl::Length::master), 2));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::twip, o3tl::Length::master), 2));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pt, o3tl::Length::master), 8));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pc, o3tl::Length::master), 96));
+static_assert(eq(o3tl::convert(125.0, o3tl::Length::in1000, o3tl::Length::master), 72));
+static_assert(eq(o3tl::convert(25.0, o3tl::Length::in100, o3tl::Length::master), 144));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in10, o3tl::Length::master), 288));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::master), 576));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::master), 6912));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::master), 36495360));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::master, o3tl::Length::master), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::px, o3tl::Length::master), 6));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ch, o3tl::Length::master), 84));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::line, o3tl::Length::master), 624));
+
+static_assert(eq(o3tl::convert(635.0, o3tl::Length::mm100, o3tl::Length::px), 24));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm10, o3tl::Length::px), 48));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::mm, o3tl::Length::px), 480));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::cm, o3tl::Length::px), 4800));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::px), 480000));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::px), 480E6));
+static_assert(eq(o3tl::convert(9525.0, o3tl::Length::emu, o3tl::Length::px), 1));
+static_assert(eq(o3tl::convert(15.0, o3tl::Length::twip, o3tl::Length::px), 1));
+static_assert(eq(o3tl::convert(3.0, o3tl::Length::pt, o3tl::Length::px), 4));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::pc, o3tl::Length::px), 16));
+static_assert(eq(o3tl::convert(125.0, o3tl::Length::in1000, o3tl::Length::px), 12));
+static_assert(eq(o3tl::convert(25.0, o3tl::Length::in100, o3tl::Length::px), 24));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::in10, o3tl::Length::px), 48));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::in, o3tl::Length::px), 96));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ft, o3tl::Length::px), 1152));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::mi, o3tl::Length::px), 6082560));
+static_assert(eq(o3tl::convert(6.0, o3tl::Length::master, o3tl::Length::px), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::px, o3tl::Length::px), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ch, o3tl::Length::px), 14));
+static_assert(eq(o3tl::convert(5.0, o3tl::Length::line, o3tl::Length::px), 104));
+
+static_assert(eq(o3tl::convert(4445.0, o3tl::Length::mm100, o3tl::Length::ch), 12));
+static_assert(eq(o3tl::convert(889.0, o3tl::Length::mm10, o3tl::Length::ch), 24));
+static_assert(eq(o3tl::convert(889.0, o3tl::Length::mm, o3tl::Length::ch), 240));
+static_assert(eq(o3tl::convert(889.0, o3tl::Length::cm, o3tl::Length::ch), 2400));
+static_assert(eq(o3tl::convert(889.0, o3tl::Length::m, o3tl::Length::ch), 240000));
+static_assert(eq(o3tl::convert(889.0, o3tl::Length::km, o3tl::Length::ch), 240E6));
+static_assert(eq(o3tl::convert(133350.0, o3tl::Length::emu, o3tl::Length::ch), 1));
+static_assert(eq(o3tl::convert(210.0, o3tl::Length::twip, o3tl::Length::ch), 1));
+static_assert(eq(o3tl::convert(21.0, o3tl::Length::pt, o3tl::Length::ch), 2));
+static_assert(eq(o3tl::convert(7.0, o3tl::Length::pc, o3tl::Length::ch), 8));
+static_assert(eq(o3tl::convert(875.0, o3tl::Length::in1000, o3tl::Length::ch), 6));
+static_assert(eq(o3tl::convert(175.0, o3tl::Length::in100, o3tl::Length::ch), 12));
+static_assert(eq(o3tl::convert(35.0, o3tl::Length::in10, o3tl::Length::ch), 24));
+static_assert(eq(o3tl::convert(7.0, o3tl::Length::in, o3tl::Length::ch), 48));
+static_assert(eq(o3tl::convert(7.0, o3tl::Length::ft, o3tl::Length::ch), 576));
+static_assert(eq(o3tl::convert(7.0, o3tl::Length::mi, o3tl::Length::ch), 3041280));
+static_assert(eq(o3tl::convert(84.0, o3tl::Length::master, o3tl::Length::ch), 1));
+static_assert(eq(o3tl::convert(14.0, o3tl::Length::px, o3tl::Length::ch), 1));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::ch, o3tl::Length::ch), 1));
+static_assert(eq(o3tl::convert(35.0, o3tl::Length::line, o3tl::Length::ch), 52));
+
+static_assert(eq(o3tl::convert(1651.0, o3tl::Length::mm100, o3tl::Length::line), 3));
+static_assert(eq(o3tl::convert(1651.0, o3tl::Length::mm10, o3tl::Length::line), 30));
+static_assert(eq(o3tl::convert(1651.0, o3tl::Length::mm, o3tl::Length::line), 300));
+static_assert(eq(o3tl::convert(1651.0, o3tl::Length::cm, o3tl::Length::line), 3000));
+static_assert(eq(o3tl::convert(1651.0, o3tl::Length::m, o3tl::Length::line), 300000));
+static_assert(eq(o3tl::convert(1651.0, o3tl::Length::km, o3tl::Length::line), 300E6));
+static_assert(eq(o3tl::convert(198120.0, o3tl::Length::emu, o3tl::Length::line), 1));
+static_assert(eq(o3tl::convert(312.0, o3tl::Length::twip, o3tl::Length::line), 1));
+static_assert(eq(o3tl::convert(78.0, o3tl::Length::pt, o3tl::Length::line), 5));
+static_assert(eq(o3tl::convert(13.0, o3tl::Length::pc, o3tl::Length::line), 10));
+static_assert(eq(o3tl::convert(650.0, o3tl::Length::in1000, o3tl::Length::line), 3));
+static_assert(eq(o3tl::convert(65.0, o3tl::Length::in100, o3tl::Length::line), 3));
+static_assert(eq(o3tl::convert(13.0, o3tl::Length::in10, o3tl::Length::line), 6));
+static_assert(eq(o3tl::convert(13.0, o3tl::Length::in, o3tl::Length::line), 60));
+static_assert(eq(o3tl::convert(13.0, o3tl::Length::ft, o3tl::Length::line), 720));
+static_assert(eq(o3tl::convert(13.0, o3tl::Length::mi, o3tl::Length::line), 3801600));
+static_assert(eq(o3tl::convert(624.0, o3tl::Length::master, o3tl::Length::line), 5));
+static_assert(eq(o3tl::convert(104.0, o3tl::Length::px, o3tl::Length::line), 5));
+static_assert(eq(o3tl::convert(52.0, o3tl::Length::ch, o3tl::Length::line), 35));
+static_assert(eq(o3tl::convert(1.0, o3tl::Length::line, o3tl::Length::line), 1));
+
+// testing integral conversion
+
+static_assert(o3tl::convert(100, o3tl::Length::mm100, o3tl::Length::mm100) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::mm10, o3tl::Length::mm100) == 1000);
+static_assert(o3tl::convert(100, o3tl::Length::mm, o3tl::Length::mm100) == 10000);
+static_assert(o3tl::convert(100, o3tl::Length::cm, o3tl::Length::mm100) == 100000);
+static_assert(o3tl::convert(100, o3tl::Length::m, o3tl::Length::mm100) == 10000000);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::mm100) == 10000000000);
+static_assert(o3tl::convert(36000, o3tl::Length::emu, o3tl::Length::mm100) == 100);
+static_assert(o3tl::convert(7200, o3tl::Length::twip, o3tl::Length::mm100) == 12700);
+static_assert(o3tl::convert(1800, o3tl::Length::pt, o3tl::Length::mm100) == 63500);
+static_assert(o3tl::convert(300, o3tl::Length::pc, o3tl::Length::mm100) == 127000);
+static_assert(o3tl::convert(5000, o3tl::Length::in1000, o3tl::Length::mm100) == 12700);
+static_assert(o3tl::convert(500, o3tl::Length::in100, o3tl::Length::mm100) == 12700);
+static_assert(o3tl::convert(100, o3tl::Length::in10, o3tl::Length::mm100) == 25400);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::mm100) == 254000);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::mm100) == 3048000);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::mm100) == 16093440000);
+static_assert(o3tl::convert(14400, o3tl::Length::master, o3tl::Length::mm100) == 63500);
+static_assert(o3tl::convert(2400, o3tl::Length::px, o3tl::Length::mm100) == 63500);
+static_assert(o3tl::convert(1200, o3tl::Length::ch, o3tl::Length::mm100) == 444500);
+static_assert(o3tl::convert(300, o3tl::Length::line, o3tl::Length::mm100) == 165100);
+
+static_assert(o3tl::convert(1000, o3tl::Length::mm100, o3tl::Length::mm10) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::mm10, o3tl::Length::mm10) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::mm, o3tl::Length::mm10) == 1000);
+static_assert(o3tl::convert(100, o3tl::Length::cm, o3tl::Length::mm10) == 10000);
+static_assert(o3tl::convert(100, o3tl::Length::m, o3tl::Length::mm10) == 1000000);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::mm10) == 1000000000);
+static_assert(o3tl::convert(360000, o3tl::Length::emu, o3tl::Length::mm10) == 100);
+static_assert(o3tl::convert(72000, o3tl::Length::twip, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(3600, o3tl::Length::pt, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(300, o3tl::Length::pc, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(50000, o3tl::Length::in1000, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(5000, o3tl::Length::in100, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(500, o3tl::Length::in10, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::mm10) == 25400);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::mm10) == 304800);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::mm10) == 1609344000);
+static_assert(o3tl::convert(28800, o3tl::Length::master, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(4800, o3tl::Length::px, o3tl::Length::mm10) == 12700);
+static_assert(o3tl::convert(2400, o3tl::Length::ch, o3tl::Length::mm10) == 88900);
+static_assert(o3tl::convert(3000, o3tl::Length::line, o3tl::Length::mm10) == 165100);
+
+static_assert(o3tl::convert(10000, o3tl::Length::mm100, o3tl::Length::mm) == 100);
+static_assert(o3tl::convert(1000, o3tl::Length::mm10, o3tl::Length::mm) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::mm, o3tl::Length::mm) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::cm, o3tl::Length::mm) == 1000);
+static_assert(o3tl::convert(100, o3tl::Length::m, o3tl::Length::mm) == 100000);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::mm) == 100000000);
+static_assert(o3tl::convert(3600000, o3tl::Length::emu, o3tl::Length::mm) == 100);
+static_assert(o3tl::convert(720000, o3tl::Length::twip, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(36000, o3tl::Length::pt, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(3000, o3tl::Length::pc, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(500000, o3tl::Length::in1000, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(50000, o3tl::Length::in100, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(5000, o3tl::Length::in10, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(500, o3tl::Length::in, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(500, o3tl::Length::ft, o3tl::Length::mm) == 152400);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::mm) == 160934400);
+static_assert(o3tl::convert(288000, o3tl::Length::master, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(48000, o3tl::Length::px, o3tl::Length::mm) == 12700);
+static_assert(o3tl::convert(24000, o3tl::Length::ch, o3tl::Length::mm) == 88900);
+static_assert(o3tl::convert(30000, o3tl::Length::line, o3tl::Length::mm) == 165100);
+
+static_assert(o3tl::convert(100000, o3tl::Length::mm100, o3tl::Length::cm) == 100);
+static_assert(o3tl::convert(10000, o3tl::Length::mm10, o3tl::Length::cm) == 100);
+static_assert(o3tl::convert(1000, o3tl::Length::mm, o3tl::Length::cm) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::cm, o3tl::Length::cm) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::m, o3tl::Length::cm) == 10000);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::cm) == 10000000);
+static_assert(o3tl::convert(36000000, o3tl::Length::emu, o3tl::Length::cm) == 100);
+static_assert(o3tl::convert(7200000, o3tl::Length::twip, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(360000, o3tl::Length::pt, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(30000, o3tl::Length::pc, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(5000000, o3tl::Length::in1000, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(500000, o3tl::Length::in100, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(50000, o3tl::Length::in10, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(5000, o3tl::Length::in, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(2500, o3tl::Length::ft, o3tl::Length::cm) == 76200);
+static_assert(o3tl::convert(500, o3tl::Length::mi, o3tl::Length::cm) == 80467200);
+static_assert(o3tl::convert(2880000, o3tl::Length::master, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(480000, o3tl::Length::px, o3tl::Length::cm) == 12700);
+static_assert(o3tl::convert(240000, o3tl::Length::ch, o3tl::Length::cm) == 88900);
+static_assert(o3tl::convert(300000, o3tl::Length::line, o3tl::Length::cm) == 165100);
+
+static_assert(o3tl::convert(10000000, o3tl::Length::mm100, o3tl::Length::m) == 100);
+static_assert(o3tl::convert(1000000, o3tl::Length::mm10, o3tl::Length::m) == 100);
+static_assert(o3tl::convert(100000, o3tl::Length::mm, o3tl::Length::m) == 100);
+static_assert(o3tl::convert(10000, o3tl::Length::cm, o3tl::Length::m) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::m, o3tl::Length::m) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::m) == 100000);
+static_assert(o3tl::convert(3600000000, o3tl::Length::emu, o3tl::Length::m) == 100);
+static_assert(o3tl::convert(720000000, o3tl::Length::twip, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(36000000, o3tl::Length::pt, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(3000000, o3tl::Length::pc, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(500000000, o3tl::Length::in1000, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(50000000, o3tl::Length::in100, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(5000000, o3tl::Length::in10, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(500000, o3tl::Length::in, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(125000, o3tl::Length::ft, o3tl::Length::m) == 38100);
+static_assert(o3tl::convert(12500, o3tl::Length::mi, o3tl::Length::m) == 20116800);
+static_assert(o3tl::convert(288000000, o3tl::Length::master, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(48000000, o3tl::Length::px, o3tl::Length::m) == 12700);
+static_assert(o3tl::convert(24000000, o3tl::Length::ch, o3tl::Length::m) == 88900);
+static_assert(o3tl::convert(30000000, o3tl::Length::line, o3tl::Length::m) == 165100);
+
+static_assert(o3tl::convert(10000000000, o3tl::Length::mm100, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(1000000000, o3tl::Length::mm10, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(100000000, o3tl::Length::mm, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(10000000, o3tl::Length::cm, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(100000, o3tl::Length::m, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(3600000000000, o3tl::Length::emu, o3tl::Length::km) == 100);
+static_assert(o3tl::convert(720000000000, o3tl::Length::twip, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(36000000000, o3tl::Length::pt, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(3000000000, o3tl::Length::pc, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(500000000000, o3tl::Length::in1000, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(50000000000, o3tl::Length::in100, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(5000000000, o3tl::Length::in10, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(500000000, o3tl::Length::in, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(125000000, o3tl::Length::ft, o3tl::Length::km) == 38100);
+static_assert(o3tl::convert(1562500, o3tl::Length::mi, o3tl::Length::km) == 2514600);
+static_assert(o3tl::convert(288000000000, o3tl::Length::master, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(48000000000, o3tl::Length::px, o3tl::Length::km) == 12700);
+static_assert(o3tl::convert(24000000000, o3tl::Length::ch, o3tl::Length::km) == 88900);
+static_assert(o3tl::convert(30000000000, o3tl::Length::line, o3tl::Length::km) == 165100);
+
+static_assert(o3tl::convert(100, o3tl::Length::mm100, o3tl::Length::emu) == 36000);
+static_assert(o3tl::convert(100, o3tl::Length::mm10, o3tl::Length::emu) == 360000);
+static_assert(o3tl::convert(100, o3tl::Length::mm, o3tl::Length::emu) == 3600000);
+static_assert(o3tl::convert(100, o3tl::Length::cm, o3tl::Length::emu) == 36000000);
+static_assert(o3tl::convert(100, o3tl::Length::m, o3tl::Length::emu) == 3600000000);
+static_assert(o3tl::convert(100, o3tl::Length::km, o3tl::Length::emu) == 3600000000000);
+static_assert(o3tl::convert(100, o3tl::Length::emu, o3tl::Length::emu) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::twip, o3tl::Length::emu) == 63500);
+static_assert(o3tl::convert(100, o3tl::Length::pt, o3tl::Length::emu) == 1270000);
+static_assert(o3tl::convert(100, o3tl::Length::pc, o3tl::Length::emu) == 15240000);
+static_assert(o3tl::convert(500, o3tl::Length::in1000, o3tl::Length::emu) == 457200);
+static_assert(o3tl::convert(100, o3tl::Length::in100, o3tl::Length::emu) == 914400);
+static_assert(o3tl::convert(100, o3tl::Length::in10, o3tl::Length::emu) == 9144000);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::emu) == 91440000);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::emu) == 1097280000);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::emu) == 5793638400000);
+static_assert(o3tl::convert(200, o3tl::Length::master, o3tl::Length::emu) == 317500);
+static_assert(o3tl::convert(100, o3tl::Length::px, o3tl::Length::emu) == 952500);
+static_assert(o3tl::convert(100, o3tl::Length::ch, o3tl::Length::emu) == 13335000);
+static_assert(o3tl::convert(100, o3tl::Length::line, o3tl::Length::emu) == 19812000);
+
+static_assert(o3tl::convert(12700, o3tl::Length::mm100, o3tl::Length::twip) == 7200);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::twip) == 72000);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::twip) == 720000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::twip) == 7200000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::twip) == 720000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::twip) == 720000000000);
+static_assert(o3tl::convert(63500, o3tl::Length::emu, o3tl::Length::twip) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::twip, o3tl::Length::twip) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::pt, o3tl::Length::twip) == 2000);
+static_assert(o3tl::convert(100, o3tl::Length::pc, o3tl::Length::twip) == 24000);
+static_assert(o3tl::convert(2500, o3tl::Length::in1000, o3tl::Length::twip) == 3600);
+static_assert(o3tl::convert(500, o3tl::Length::in100, o3tl::Length::twip) == 7200);
+static_assert(o3tl::convert(100, o3tl::Length::in10, o3tl::Length::twip) == 14400);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::twip) == 144000);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::twip) == 1728000);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::twip) == 9123840000);
+static_assert(o3tl::convert(200, o3tl::Length::master, o3tl::Length::twip) == 500);
+static_assert(o3tl::convert(100, o3tl::Length::px, o3tl::Length::twip) == 1500);
+static_assert(o3tl::convert(100, o3tl::Length::ch, o3tl::Length::twip) == 21000);
+static_assert(o3tl::convert(100, o3tl::Length::line, o3tl::Length::twip) == 31200);
+
+static_assert(o3tl::convert(63500, o3tl::Length::mm100, o3tl::Length::pt) == 1800);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::pt) == 3600);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::pt) == 36000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::pt) == 360000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::pt) == 36000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::pt) == 36000000000);
+static_assert(o3tl::convert(1270000, o3tl::Length::emu, o3tl::Length::pt) == 100);
+static_assert(o3tl::convert(2000, o3tl::Length::twip, o3tl::Length::pt) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::pt, o3tl::Length::pt) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::pc, o3tl::Length::pt) == 1200);
+static_assert(o3tl::convert(12500, o3tl::Length::in1000, o3tl::Length::pt) == 900);
+static_assert(o3tl::convert(2500, o3tl::Length::in100, o3tl::Length::pt) == 1800);
+static_assert(o3tl::convert(500, o3tl::Length::in10, o3tl::Length::pt) == 3600);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::pt) == 7200);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::pt) == 86400);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::pt) == 456192000);
+static_assert(o3tl::convert(800, o3tl::Length::master, o3tl::Length::pt) == 100);
+static_assert(o3tl::convert(400, o3tl::Length::px, o3tl::Length::pt) == 300);
+static_assert(o3tl::convert(200, o3tl::Length::ch, o3tl::Length::pt) == 2100);
+static_assert(o3tl::convert(500, o3tl::Length::line, o3tl::Length::pt) == 7800);
+
+static_assert(o3tl::convert(127000, o3tl::Length::mm100, o3tl::Length::pc) == 300);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::pc) == 300);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::pc) == 3000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::pc) == 30000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::pc) == 3000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::pc) == 3000000000);
+static_assert(o3tl::convert(15240000, o3tl::Length::emu, o3tl::Length::pc) == 100);
+static_assert(o3tl::convert(24000, o3tl::Length::twip, o3tl::Length::pc) == 100);
+static_assert(o3tl::convert(1200, o3tl::Length::pt, o3tl::Length::pc) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::pc, o3tl::Length::pc) == 100);
+static_assert(o3tl::convert(50000, o3tl::Length::in1000, o3tl::Length::pc) == 300);
+static_assert(o3tl::convert(5000, o3tl::Length::in100, o3tl::Length::pc) == 300);
+static_assert(o3tl::convert(500, o3tl::Length::in10, o3tl::Length::pc) == 300);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::pc) == 600);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::pc) == 7200);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::pc) == 38016000);
+static_assert(o3tl::convert(9600, o3tl::Length::master, o3tl::Length::pc) == 100);
+static_assert(o3tl::convert(1600, o3tl::Length::px, o3tl::Length::pc) == 100);
+static_assert(o3tl::convert(800, o3tl::Length::ch, o3tl::Length::pc) == 700);
+static_assert(o3tl::convert(1000, o3tl::Length::line, o3tl::Length::pc) == 1300);
+
+static_assert(o3tl::convert(12700, o3tl::Length::mm100, o3tl::Length::in1000) == 5000);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::in1000) == 50000);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::in1000) == 500000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::in1000) == 5000000);
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::m, o3tl::Length::in1000), 5E6));
+static_assert(eq(o3tl::convert(127.0, o3tl::Length::km, o3tl::Length::in1000), 5E9));
+static_assert(o3tl::convert(457200, o3tl::Length::emu, o3tl::Length::in1000) == 500);
+static_assert(o3tl::convert(3600, o3tl::Length::twip, o3tl::Length::in1000) == 2500);
+static_assert(o3tl::convert(900, o3tl::Length::pt, o3tl::Length::in1000) == 12500);
+static_assert(o3tl::convert(300, o3tl::Length::pc, o3tl::Length::in1000) == 50000);
+static_assert(o3tl::convert(100, o3tl::Length::in1000, o3tl::Length::in1000) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::in100, o3tl::Length::in1000) == 1000);
+static_assert(o3tl::convert(100, o3tl::Length::in10, o3tl::Length::in1000) == 10000);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::in1000) == 100000);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::in1000) == 1200000);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::in1000) == 6336000000);
+static_assert(o3tl::convert(7200, o3tl::Length::master, o3tl::Length::in1000) == 12500);
+static_assert(o3tl::convert(1200, o3tl::Length::px, o3tl::Length::in1000) == 12500);
+static_assert(o3tl::convert(600, o3tl::Length::ch, o3tl::Length::in1000) == 87500);
+static_assert(o3tl::convert(300, o3tl::Length::line, o3tl::Length::in1000) == 65000);
+
+static_assert(o3tl::convert(12700, o3tl::Length::mm100, o3tl::Length::in100) == 500);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::in100) == 5000);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::in100) == 50000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::in100) == 500000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::in100) == 50000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::in100) == 50000000000);
+static_assert(o3tl::convert(914400, o3tl::Length::emu, o3tl::Length::in100) == 100);
+static_assert(o3tl::convert(7200, o3tl::Length::twip, o3tl::Length::in100) == 500);
+static_assert(o3tl::convert(1800, o3tl::Length::pt, o3tl::Length::in100) == 2500);
+static_assert(o3tl::convert(300, o3tl::Length::pc, o3tl::Length::in100) == 5000);
+static_assert(o3tl::convert(1000, o3tl::Length::in1000, o3tl::Length::in100) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::in100, o3tl::Length::in100) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::in10, o3tl::Length::in100) == 1000);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::in100) == 10000);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::in100) == 120000);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::in100) == 633600000);
+static_assert(o3tl::convert(14400, o3tl::Length::master, o3tl::Length::in100) == 2500);
+static_assert(o3tl::convert(2400, o3tl::Length::px, o3tl::Length::in100) == 2500);
+static_assert(o3tl::convert(1200, o3tl::Length::ch, o3tl::Length::in100) == 17500);
+static_assert(o3tl::convert(300, o3tl::Length::line, o3tl::Length::in100) == 6500);
+
+static_assert(o3tl::convert(25400, o3tl::Length::mm100, o3tl::Length::in10) == 100);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::in10) == 500);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::in10) == 5000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::in10) == 50000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::in10) == 5000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::in10) == 5000000000);
+static_assert(o3tl::convert(9144000, o3tl::Length::emu, o3tl::Length::in10) == 100);
+static_assert(o3tl::convert(14400, o3tl::Length::twip, o3tl::Length::in10) == 100);
+static_assert(o3tl::convert(3600, o3tl::Length::pt, o3tl::Length::in10) == 500);
+static_assert(o3tl::convert(300, o3tl::Length::pc, o3tl::Length::in10) == 500);
+static_assert(o3tl::convert(10000, o3tl::Length::in1000, o3tl::Length::in10) == 100);
+static_assert(o3tl::convert(1000, o3tl::Length::in100, o3tl::Length::in10) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::in10, o3tl::Length::in10) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::in10) == 1000);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::in10) == 12000);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::in10) == 63360000);
+static_assert(o3tl::convert(28800, o3tl::Length::master, o3tl::Length::in10) == 500);
+static_assert(o3tl::convert(4800, o3tl::Length::px, o3tl::Length::in10) == 500);
+static_assert(o3tl::convert(2400, o3tl::Length::ch, o3tl::Length::in10) == 3500);
+static_assert(o3tl::convert(600, o3tl::Length::line, o3tl::Length::in10) == 1300);
+
+static_assert(o3tl::convert(254000, o3tl::Length::mm100, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(25400, o3tl::Length::mm10, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::in) == 500);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::in) == 5000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::in) == 500000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::in) == 500000000);
+static_assert(o3tl::convert(91440000, o3tl::Length::emu, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(144000, o3tl::Length::twip, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(7200, o3tl::Length::pt, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(600, o3tl::Length::pc, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(100000, o3tl::Length::in1000, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(10000, o3tl::Length::in100, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(1000, o3tl::Length::in10, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::in) == 1200);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::in) == 6336000);
+static_assert(o3tl::convert(57600, o3tl::Length::master, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(9600, o3tl::Length::px, o3tl::Length::in) == 100);
+static_assert(o3tl::convert(4800, o3tl::Length::ch, o3tl::Length::in) == 700);
+static_assert(o3tl::convert(6000, o3tl::Length::line, o3tl::Length::in) == 1300);
+
+static_assert(o3tl::convert(3048000, o3tl::Length::mm100, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(304800, o3tl::Length::mm10, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(152400, o3tl::Length::mm, o3tl::Length::ft) == 500);
+static_assert(o3tl::convert(76200, o3tl::Length::cm, o3tl::Length::ft) == 2500);
+static_assert(o3tl::convert(38100, o3tl::Length::m, o3tl::Length::ft) == 125000);
+static_assert(o3tl::convert(38100, o3tl::Length::km, o3tl::Length::ft) == 125000000);
+static_assert(o3tl::convert(1097280000, o3tl::Length::emu, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(1728000, o3tl::Length::twip, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(86400, o3tl::Length::pt, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(7200, o3tl::Length::pc, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(1200000, o3tl::Length::in1000, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(120000, o3tl::Length::in100, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(12000, o3tl::Length::in10, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(1200, o3tl::Length::in, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::ft) == 528000);
+static_assert(o3tl::convert(691200, o3tl::Length::master, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(115200, o3tl::Length::px, o3tl::Length::ft) == 100);
+static_assert(o3tl::convert(57600, o3tl::Length::ch, o3tl::Length::ft) == 700);
+static_assert(o3tl::convert(72000, o3tl::Length::line, o3tl::Length::ft) == 1300);
+
+static_assert(o3tl::convert(16093440000, o3tl::Length::mm100, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(1609344000, o3tl::Length::mm10, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(160934400, o3tl::Length::mm, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(80467200, o3tl::Length::cm, o3tl::Length::mi) == 500);
+static_assert(o3tl::convert(20116800, o3tl::Length::m, o3tl::Length::mi) == 12500);
+static_assert(o3tl::convert(2514600, o3tl::Length::km, o3tl::Length::mi) == 1562500);
+static_assert(o3tl::convert(5793638400000, o3tl::Length::emu, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(9123840000, o3tl::Length::twip, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(456192000, o3tl::Length::pt, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(38016000, o3tl::Length::pc, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(6336000000, o3tl::Length::in1000, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(633600000, o3tl::Length::in100, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(63360000, o3tl::Length::in10, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(6336000, o3tl::Length::in, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(528000, o3tl::Length::ft, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(3649536000, o3tl::Length::master, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(608256000, o3tl::Length::px, o3tl::Length::mi) == 100);
+static_assert(o3tl::convert(304128000, o3tl::Length::ch, o3tl::Length::mi) == 700);
+static_assert(o3tl::convert(380160000, o3tl::Length::line, o3tl::Length::mi) == 1300);
+
+static_assert(o3tl::convert(63500, o3tl::Length::mm100, o3tl::Length::master) == 14400);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::master) == 28800);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::master) == 288000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::master) == 2880000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::master) == 288000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::master) == 288000000000);
+static_assert(o3tl::convert(317500, o3tl::Length::emu, o3tl::Length::master) == 200);
+static_assert(o3tl::convert(500, o3tl::Length::twip, o3tl::Length::master) == 200);
+static_assert(o3tl::convert(100, o3tl::Length::pt, o3tl::Length::master) == 800);
+static_assert(o3tl::convert(100, o3tl::Length::pc, o3tl::Length::master) == 9600);
+static_assert(o3tl::convert(12500, o3tl::Length::in1000, o3tl::Length::master) == 7200);
+static_assert(o3tl::convert(2500, o3tl::Length::in100, o3tl::Length::master) == 14400);
+static_assert(o3tl::convert(500, o3tl::Length::in10, o3tl::Length::master) == 28800);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::master) == 57600);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::master) == 691200);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::master) == 3649536000);
+static_assert(o3tl::convert(100, o3tl::Length::master, o3tl::Length::master) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::px, o3tl::Length::master) == 600);
+static_assert(o3tl::convert(100, o3tl::Length::ch, o3tl::Length::master) == 8400);
+static_assert(o3tl::convert(500, o3tl::Length::line, o3tl::Length::master) == 62400);
+
+static_assert(o3tl::convert(63500, o3tl::Length::mm100, o3tl::Length::px) == 2400);
+static_assert(o3tl::convert(12700, o3tl::Length::mm10, o3tl::Length::px) == 4800);
+static_assert(o3tl::convert(12700, o3tl::Length::mm, o3tl::Length::px) == 48000);
+static_assert(o3tl::convert(12700, o3tl::Length::cm, o3tl::Length::px) == 480000);
+static_assert(o3tl::convert(12700, o3tl::Length::m, o3tl::Length::px) == 48000000);
+static_assert(o3tl::convert(12700, o3tl::Length::km, o3tl::Length::px) == 48000000000);
+static_assert(o3tl::convert(952500, o3tl::Length::emu, o3tl::Length::px) == 100);
+static_assert(o3tl::convert(1500, o3tl::Length::twip, o3tl::Length::px) == 100);
+static_assert(o3tl::convert(300, o3tl::Length::pt, o3tl::Length::px) == 400);
+static_assert(o3tl::convert(100, o3tl::Length::pc, o3tl::Length::px) == 1600);
+static_assert(o3tl::convert(12500, o3tl::Length::in1000, o3tl::Length::px) == 1200);
+static_assert(o3tl::convert(2500, o3tl::Length::in100, o3tl::Length::px) == 2400);
+static_assert(o3tl::convert(500, o3tl::Length::in10, o3tl::Length::px) == 4800);
+static_assert(o3tl::convert(100, o3tl::Length::in, o3tl::Length::px) == 9600);
+static_assert(o3tl::convert(100, o3tl::Length::ft, o3tl::Length::px) == 115200);
+static_assert(o3tl::convert(100, o3tl::Length::mi, o3tl::Length::px) == 608256000);
+static_assert(o3tl::convert(600, o3tl::Length::master, o3tl::Length::px) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::px, o3tl::Length::px) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::ch, o3tl::Length::px) == 1400);
+static_assert(o3tl::convert(500, o3tl::Length::line, o3tl::Length::px) == 10400);
+
+static_assert(o3tl::convert(444500, o3tl::Length::mm100, o3tl::Length::ch) == 1200);
+static_assert(o3tl::convert(88900, o3tl::Length::mm10, o3tl::Length::ch) == 2400);
+static_assert(o3tl::convert(88900, o3tl::Length::mm, o3tl::Length::ch) == 24000);
+static_assert(o3tl::convert(88900, o3tl::Length::cm, o3tl::Length::ch) == 240000);
+static_assert(o3tl::convert(88900, o3tl::Length::m, o3tl::Length::ch) == 24000000);
+static_assert(o3tl::convert(88900, o3tl::Length::km, o3tl::Length::ch) == 24000000000);
+static_assert(o3tl::convert(13335000, o3tl::Length::emu, o3tl::Length::ch) == 100);
+static_assert(o3tl::convert(21000, o3tl::Length::twip, o3tl::Length::ch) == 100);
+static_assert(o3tl::convert(2100, o3tl::Length::pt, o3tl::Length::ch) == 200);
+static_assert(o3tl::convert(700, o3tl::Length::pc, o3tl::Length::ch) == 800);
+static_assert(o3tl::convert(87500, o3tl::Length::in1000, o3tl::Length::ch) == 600);
+static_assert(o3tl::convert(17500, o3tl::Length::in100, o3tl::Length::ch) == 1200);
+static_assert(o3tl::convert(3500, o3tl::Length::in10, o3tl::Length::ch) == 2400);
+static_assert(o3tl::convert(700, o3tl::Length::in, o3tl::Length::ch) == 4800);
+static_assert(o3tl::convert(700, o3tl::Length::ft, o3tl::Length::ch) == 57600);
+static_assert(o3tl::convert(700, o3tl::Length::mi, o3tl::Length::ch) == 304128000);
+static_assert(o3tl::convert(8400, o3tl::Length::master, o3tl::Length::ch) == 100);
+static_assert(o3tl::convert(1400, o3tl::Length::px, o3tl::Length::ch) == 100);
+static_assert(o3tl::convert(100, o3tl::Length::ch, o3tl::Length::ch) == 100);
+static_assert(o3tl::convert(3500, o3tl::Length::line, o3tl::Length::ch) == 5200);
+
+static_assert(o3tl::convert(165100, o3tl::Length::mm100, o3tl::Length::line) == 300);
+static_assert(o3tl::convert(165100, o3tl::Length::mm10, o3tl::Length::line) == 3000);
+static_assert(o3tl::convert(165100, o3tl::Length::mm, o3tl::Length::line) == 30000);
+static_assert(o3tl::convert(165100, o3tl::Length::cm, o3tl::Length::line) == 300000);
+static_assert(o3tl::convert(165100, o3tl::Length::m, o3tl::Length::line) == 30000000);
+static_assert(o3tl::convert(165100, o3tl::Length::km, o3tl::Length::line) == 30000000000);
+static_assert(o3tl::convert(19812000, o3tl::Length::emu, o3tl::Length::line) == 100);
+static_assert(o3tl::convert(31200, o3tl::Length::twip, o3tl::Length::line) == 100);
+static_assert(o3tl::convert(7800, o3tl::Length::pt, o3tl::Length::line) == 500);
+static_assert(o3tl::convert(1300, o3tl::Length::pc, o3tl::Length::line) == 1000);
+static_assert(o3tl::convert(65000, o3tl::Length::in1000, o3tl::Length::line) == 300);
+static_assert(o3tl::convert(6500, o3tl::Length::in100, o3tl::Length::line) == 300);
+static_assert(o3tl::convert(1300, o3tl::Length::in10, o3tl::Length::line) == 600);
+static_assert(o3tl::convert(1300, o3tl::Length::in, o3tl::Length::line) == 6000);
+static_assert(o3tl::convert(1300, o3tl::Length::ft, o3tl::Length::line) == 72000);
+static_assert(o3tl::convert(1300, o3tl::Length::mi, o3tl::Length::line) == 380160000);
+static_assert(o3tl::convert(62400, o3tl::Length::master, o3tl::Length::line) == 500);
+static_assert(o3tl::convert(10400, o3tl::Length::px, o3tl::Length::line) == 500);
+static_assert(o3tl::convert(5200, o3tl::Length::ch, o3tl::Length::line) == 3500);
+static_assert(o3tl::convert(100, o3tl::Length::line, o3tl::Length::line) == 100);
+
+// Integral rounding
+
+static_assert(o3tl::convert(49, o3tl::Length::mm100, o3tl::Length::mm) == 0);
+static_assert(o3tl::convert(50, o3tl::Length::mm100, o3tl::Length::mm) == 1);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/oox/source/drawingml/diagram/diagram.cxx b/oox/source/drawingml/diagram/diagram.cxx
index 9a8f727b9070..28c79e8cbd60 100644
--- a/oox/source/drawingml/diagram/diagram.cxx
+++ b/oox/source/drawingml/diagram/diagram.cxx
@@ -30,6 +30,7 @@
 #include <editeng/unoprnms.hxx>
 #include <drawingml/fillproperties.hxx>
 #include <drawingml/customshapeproperties.hxx>
+#include <o3tl/unit_conversion.hxx>
 #include <oox/token/namespaces.hxx>
 #include <basegfx/matrix/b2dhommatrix.hxx>
 #include <svx/svdpage.hxx>
@@ -439,15 +440,17 @@ void reloadDiagram(SdrObject* pObj, core::XmlFilterBase& rFilter)
 
     ShapePtr pShape = std::make_shared<Shape>();
     pShape->setDiagramType();
-    pShape->setSize(awt::Size(xShape->getSize().Width * EMU_PER_HMM,
-                              xShape->getSize().Height * EMU_PER_HMM));
+    pShape->setSize(
+        awt::Size(o3tl::convert(xShape->getSize().Width, o3tl::Length::mm100, o3tl::Length::emu),
+                  o3tl::convert(xShape->getSize().Height, o3tl::Length::mm100, o3tl::Length::emu)));
 
     loadDiagram(pShape, pDiagramData, layoutDom, styleDom, colorDom, rFilter);
 
     uno::Reference<drawing::XShapes> xShapes(xShape, uno::UNO_QUERY_THROW);
     basegfx::B2DHomMatrix aTransformation;
-    aTransformation.translate(xShape->getPosition().X * EMU_PER_HMM,
-                              xShape->getPosition().Y * EMU_PER_HMM);
+    aTransformation.translate(
+        o3tl::convert(xShape->getPosition().X, o3tl::Length::mm100, o3tl::Length::emu),
+        o3tl::convert(xShape->getPosition().Y, o3tl::Length::mm100, o3tl::Length::emu));
     for (auto const& child : pShape->getChildren())
         child->addShape(rFilter, rFilter.getCurrentTheme(), xShapes, aTransformation, pShape->getFillProperties());
 }
diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
index 66df25d9ef4a..bc24b0322059 100644
--- a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
+++ b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
@@ -26,6 +26,7 @@
 #include <basegfx/numeric/ftools.hxx>
 #include <sal/log.hxx>
 
+#include <o3tl/unit_conversion.hxx>
 #include <oox/helper/attributelist.hxx>
 #include <oox/token/properties.hxx>
 #include <drawingml/fillproperties.hxx>
@@ -538,14 +539,11 @@ void CompositeAlg::applyConstraintToLayout(const Constraint& rConstraint,
         // Reference not found, assume a fixed value.
         // Values are never in EMU, while oox::drawingml::Shape position and size are always in
         // EMU.
-        double fUnitFactor = 0;
-        if (isFontUnit(rConstraint.mnRefType))
-            // Points -> EMU.
-            fUnitFactor = EMU_PER_PT;
-        else
-            // Millimeters -> EMU.
-            fUnitFactor = EMU_PER_HMM * 100;
-        rProperties[rConstraint.msForName][rConstraint.mnType] = rConstraint.mfValue * fUnitFactor;
+        const double fValue = o3tl::convert(rConstraint.mfValue,
+                                            isFontUnit(rConstraint.mnRefType) ? o3tl::Length::pt
+                                                                              : o3tl::Length::mm,
+                                            o3tl::Length::emu);
+        rProperties[rConstraint.msForName][rConstraint.mnType] = fValue;
     }
 }
 
@@ -1709,7 +1707,8 @@ void AlgAtom::layoutShape(const ShapePtr& rShape, const std::vector<Constraint>&
                     double fFactor = convertPointToMms(rConstr.mfFactor);
 
                     // DrawingML works in EMUs, UNO API works in MM100s.
-                    sal_Int32 nValue = rShape->getSize().Width * fFactor / EMU_PER_HMM;
+                    sal_Int32 nValue = o3tl::convert(rShape->getSize().Width * fFactor,
+                                                     o3tl::Length::emu, o3tl::Length::mm100);
 
                     rShape->getShapeProperties().setProperty(nProperty, nValue);
                 }
@@ -1816,12 +1815,15 @@ void AlgAtom::layoutShape(const ShapePtr& rShape, const std::vector<Constraint>&
                 {
                     if (!aParagraph->getProperties().getParaLeftMargin().has_value())
                     {
-                        sal_Int32 nLeftMargin = 285750 * (nLevel - nStartBulletsAtLevel + 1) / EMU_PER_HMM;
+                        sal_Int32 nLeftMargin
+                            = o3tl::convert(285750 * (nLevel - nStartBulletsAtLevel + 1),
+                                            o3tl::Length::emu, o3tl::Length::mm100);
                         aParagraph->getProperties().getParaLeftMargin() = nLeftMargin;
                     }
 
                     if (!aParagraph->getProperties().getFirstLineIndentation().has_value())
-                        aParagraph->getProperties().getFirstLineIndentation() = -285750 / EMU_PER_HMM;
+                        aParagraph->getProperties().getFirstLineIndentation()
+                            = o3tl::convert(-285750, o3tl::Length::emu, o3tl::Length::mm100);
 
                     // It is not possible to change the bullet style for text.
                     aParagraph->getProperties().getBulletList().setBulletChar(u"•");
diff --git a/oox/source/drawingml/drawingmltypes.cxx b/oox/source/drawingml/drawingmltypes.cxx
index 645fe9ec9221..3a94a449f317 100644
--- a/oox/source/drawingml/drawingmltypes.cxx
+++ b/oox/source/drawingml/drawingmltypes.cxx
@@ -40,8 +40,7 @@ namespace oox::drawingml {
 /** converts EMUs into 1/100th mmm */
 sal_Int32 GetCoordinate( sal_Int32 nValue )
 {
-    nValue = o3tl::saturating_add<sal_Int32>(nValue, 180);
-    return nValue / 360;
+    return o3tl::convert(nValue, o3tl::Length::emu, o3tl::Length::mm100);
 }
 
 /** converts an emu string into 1/100th mmm */
@@ -56,7 +55,7 @@ sal_Int32 GetCoordinate( std::u16string_view sValue )
 /** converts 1/100mm to EMU */
 sal_Int32 GetPointFromCoordinate( sal_Int32 nValue )
 {
-    return nValue * 360;
+    return o3tl::convert(nValue, o3tl::Length::mm100, o3tl::Length::emu);
 }
 
 /** converts a ST_Percentage % string into 1/1000th of % */
diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx
index b4ce27ea4df4..22cacec6eaa6 100644
--- a/oox/source/drawingml/shape.cxx
+++ b/oox/source/drawingml/shape.cxx
@@ -35,6 +35,7 @@
 #include <drawingml/chart/chartspacefragment.hxx>
 #include <drawingml/chart/chartspacemodel.hxx>
 #include <o3tl/safeint.hxx>
+#include <o3tl/unit_conversion.hxx>
 #include <oox/ppt/pptimport.hxx>
 #include <oox/vml/vmldrawing.hxx>
 #include <oox/vml/vmlshape.hxx>
@@ -699,7 +700,11 @@ Reference< XShape > const & Shape::createAndInsert(
         }
     }
 

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list