Next / Previous / Contents / Shipman's homepage

9.9. FoDim.confactor(): Find the conversion factor between two units

We support the dimensional-unit codes defined in Section 7.2, “Dimensional units”.

Some conversions are exact (e.g., cm to mm and pc to pt), while others are approximate. We would like to use exact conversions where possible, so we order the units into a sequence named unitList, and group units together if they have exact conversions. We define another sequence factorList that specifies the conversion factors between two adjacent units in this sequence. Then, the problem of converting arbitrary units reduces to finding the position of the old and new units within this sequence, and finding the product of the conversion factors for each step.
# - - -   F o D i m . c o n f a c t o r  (static method)

    factorList = ( Decimal(12),        # 1pc = 12pt
        Decimal(1)/Decimal('72.27'),   # 1pt = 1/72.27in
        Decimal('2.54'),               # 1in = 2.54cm
        Decimal(10) )                  # 1cm = 10mm

    def confactor(fromUnits, toUnits):
        '''Find any arbitrary conversion factor.

          [ fromUnits and toUnits are XSL-FO dimensional units ->
              return the factor that must be multiplied by a
              quantity using fromUnits to express it as toUnits ]

The first step is to locate the two units by their position in unitList. Note that this step will raise ValueError if the units are not standard XSL-FO units.
        #-- 1 --
        # [ fromPos  :=  position of fromUnits in unitList
        #   toPos  :=  position of toUnits in unitList
        #   result  :=  Decimal(1) ]
        fromPos = FoDim.unitList.index(fromUnits)
        toPos = FoDim.unitList.index(toUnits)
        result = Decimal(1)

To move from lower-numbered units to higher ones, we multiple the result by the factors for each step. In the reverse direction, we divide by those factors. If fromPos==toPos, the result remains at value 1.0.
        #-- 2 --
        # [ if fromPos < toPos ->
        #     result  *:=  elements of FoDim.factorList in positions
        #         fromPos, fromPos+1, ..., toPos-1, inclusive
        #   else if fromPos > toPos ->
        #     result  /:=  elements of FoDim.factorList in positions
        #         fromPos-1, fromPos-2, ..., toPos, inclusive ]
        if fromPos < toPos:
            for pos in range(fromPos, toPos):
                result *= FoDim.factorList[pos]
        elif fromPos > toPos:
            for pos in range(fromPos-1, toPos-1, -1):
                result /= FoDim.factorList[pos]

        #-- 3 --
        return result