Blame src/units.cpp

Packit Service 7770af
#include "sass.hpp"
Packit Service 7770af
#include <stdexcept>
Packit Service 7770af
#include "units.hpp"
Packit Service 7770af
#include "error_handling.hpp"
Packit Service 7770af
Packit Service 7770af
namespace Sass {
Packit Service 7770af
Packit Service 7770af
  /* the conversion matrix can be readed the following way */
Packit Service 7770af
  /* if you go down, the factor is for the numerator (multiply) */
Packit Service 7770af
  /* if you go right, the factor is for the denominator (divide) */
Packit Service 7770af
  /* and yes, we actually use both, not sure why, but why not!? */
Packit Service 7770af
Packit Service 7770af
  const double size_conversion_factors[6][6] =
Packit Service 7770af
  {
Packit Service 7770af
             /*  in         cm         pc         mm         pt         px        */
Packit Service 7770af
    /* in   */ { 1,         2.54,      6,         25.4,      72,        96,       },
Packit Service 7770af
    /* cm   */ { 1.0/2.54,  1,         6.0/2.54,  10,        72.0/2.54, 96.0/2.54 },
Packit Service 7770af
    /* pc   */ { 1.0/6.0,   2.54/6.0,  1,         25.4/6.0,  72.0/6.0,  96.0/6.0  },
Packit Service 7770af
    /* mm   */ { 1.0/25.4,  1.0/10.0,  6.0/25.4,  1,         72.0/25.4, 96.0/25.4 },
Packit Service 7770af
    /* pt   */ { 1.0/72.0,  2.54/72.0, 6.0/72.0,  25.4/72.0, 1,         96.0/72.0 },
Packit Service 7770af
    /* px   */ { 1.0/96.0,  2.54/96.0, 6.0/96.0,  25.4/96.0, 72.0/96.0, 1,        }
Packit Service 7770af
  };
Packit Service 7770af
Packit Service 7770af
  const double angle_conversion_factors[4][4] =
Packit Service 7770af
  {
Packit Service 7770af
             /*  deg        grad       rad        turn      */
Packit Service 7770af
    /* deg  */ { 1,         40.0/36.0, PI/180.0,  1.0/360.0 },
Packit Service 7770af
    /* grad */ { 36.0/40.0, 1,         PI/200.0,  1.0/400.0 },
Packit Service 7770af
    /* rad  */ { 180.0/PI,  200.0/PI,  1,         0.5/PI    },
Packit Service 7770af
    /* turn */ { 360.0,     400.0,     2.0*PI,    1         }
Packit Service 7770af
  };
Packit Service 7770af
Packit Service 7770af
  const double time_conversion_factors[2][2] =
Packit Service 7770af
  {
Packit Service 7770af
             /*  s          ms        */
Packit Service 7770af
    /* s    */ { 1,         1000.0    },
Packit Service 7770af
    /* ms   */ { 1/1000.0,  1         }
Packit Service 7770af
  };
Packit Service 7770af
  const double frequency_conversion_factors[2][2] =
Packit Service 7770af
  {
Packit Service 7770af
             /*  Hz         kHz       */
Packit Service 7770af
    /* Hz   */ { 1,         1/1000.0  },
Packit Service 7770af
    /* kHz  */ { 1000.0,    1         }
Packit Service 7770af
  };
Packit Service 7770af
  const double resolution_conversion_factors[3][3] =
Packit Service 7770af
  {
Packit Service 7770af
             /*  dpi        dpcm       dppx     */
Packit Service 7770af
    /* dpi  */ { 1,         1/2.54,    1/96.0   },
Packit Service 7770af
    /* dpcm */ { 2.54,      1,         2.54/96  },
Packit Service 7770af
    /* dppx */ { 96,        96/2.54,   1        }
Packit Service 7770af
  };
Packit Service 7770af
Packit Service 7770af
  UnitClass get_unit_type(UnitType unit)
Packit Service 7770af
  {
Packit Service 7770af
    switch (unit & 0xFF00)
Packit Service 7770af
    {
Packit Service 7770af
      case UnitClass::LENGTH:      return UnitClass::LENGTH;
Packit Service 7770af
      case UnitClass::ANGLE:       return UnitClass::ANGLE;
Packit Service 7770af
      case UnitClass::TIME:        return UnitClass::TIME;
Packit Service 7770af
      case UnitClass::FREQUENCY:   return UnitClass::FREQUENCY;
Packit Service 7770af
      case UnitClass::RESOLUTION:  return UnitClass::RESOLUTION;
Packit Service 7770af
      default:                     return UnitClass::INCOMMENSURABLE;
Packit Service 7770af
    }
Packit Service 7770af
  };
Packit Service 7770af
Packit Service 7770af
  std::string get_unit_class(UnitType unit)
Packit Service 7770af
  {
Packit Service 7770af
    switch (unit & 0xFF00)
Packit Service 7770af
    {
Packit Service 7770af
      case UnitClass::LENGTH:      return "LENGTH";
Packit Service 7770af
      case UnitClass::ANGLE:       return "ANGLE";
Packit Service 7770af
      case UnitClass::TIME:        return "TIME";
Packit Service 7770af
      case UnitClass::FREQUENCY:   return "FREQUENCY";
Packit Service 7770af
      case UnitClass::RESOLUTION:  return "RESOLUTION";
Packit Service 7770af
      default:                     return "INCOMMENSURABLE";
Packit Service 7770af
    }
Packit Service 7770af
  };
Packit Service 7770af
Packit Service 7770af
  UnitType string_to_unit(const std::string& s)
Packit Service 7770af
  {
Packit Service 7770af
    // size units
Packit Service 7770af
    if      (s == "px")   return UnitType::PX;
Packit Service 7770af
    else if (s == "pt")   return UnitType::PT;
Packit Service 7770af
    else if (s == "pc")   return UnitType::PC;
Packit Service 7770af
    else if (s == "mm")   return UnitType::MM;
Packit Service 7770af
    else if (s == "cm")   return UnitType::CM;
Packit Service 7770af
    else if (s == "in")   return UnitType::IN;
Packit Service 7770af
    // angle units
Packit Service 7770af
    else if (s == "deg")  return UnitType::DEG;
Packit Service 7770af
    else if (s == "grad") return UnitType::GRAD;
Packit Service 7770af
    else if (s == "rad")  return UnitType::RAD;
Packit Service 7770af
    else if (s == "turn") return UnitType::TURN;
Packit Service 7770af
    // time units
Packit Service 7770af
    else if (s == "s")    return UnitType::SEC;
Packit Service 7770af
    else if (s == "ms")   return UnitType::MSEC;
Packit Service 7770af
    // frequency units
Packit Service 7770af
    else if (s == "Hz")   return UnitType::HERTZ;
Packit Service 7770af
    else if (s == "kHz")  return UnitType::KHERTZ;
Packit Service 7770af
    // resolutions units
Packit Service 7770af
    else if (s == "dpi")  return UnitType::DPI;
Packit Service 7770af
    else if (s == "dpcm") return UnitType::DPCM;
Packit Service 7770af
    else if (s == "dppx") return UnitType::DPPX;
Packit Service 7770af
    // for unknown units
Packit Service 7770af
    else return UnitType::UNKNOWN;
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  const char* unit_to_string(UnitType unit)
Packit Service 7770af
  {
Packit Service 7770af
    switch (unit) {
Packit Service 7770af
      // size units
Packit Service 7770af
      case UnitType::PX:      return "px";
Packit Service 7770af
      case UnitType::PT:      return "pt";
Packit Service 7770af
      case UnitType::PC:      return "pc";
Packit Service 7770af
      case UnitType::MM:      return "mm";
Packit Service 7770af
      case UnitType::CM:      return "cm";
Packit Service 7770af
      case UnitType::IN:      return "in";
Packit Service 7770af
      // angle units
Packit Service 7770af
      case UnitType::DEG:     return "deg";
Packit Service 7770af
      case UnitType::GRAD:    return "grad";
Packit Service 7770af
      case UnitType::RAD:     return "rad";
Packit Service 7770af
      case UnitType::TURN:    return "turn";
Packit Service 7770af
      // time units
Packit Service 7770af
      case UnitType::SEC:     return "s";
Packit Service 7770af
      case UnitType::MSEC:    return "ms";
Packit Service 7770af
      // frequency units
Packit Service 7770af
      case UnitType::HERTZ:   return "Hz";
Packit Service 7770af
      case UnitType::KHERTZ:  return "kHz";
Packit Service 7770af
      // resolutions units
Packit Service 7770af
      case UnitType::DPI:     return "dpi";
Packit Service 7770af
      case UnitType::DPCM:    return "dpcm";
Packit Service 7770af
      case UnitType::DPPX:    return "dppx";
Packit Service 7770af
      // for unknown units
Packit Service 7770af
      default:                return "";
Packit Service 7770af
    }
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  std::string unit_to_class(const std::string& s)
Packit Service 7770af
  {
Packit Service 7770af
    if      (s == "px")   return "LENGTH";
Packit Service 7770af
    else if (s == "pt")   return "LENGTH";
Packit Service 7770af
    else if (s == "pc")   return "LENGTH";
Packit Service 7770af
    else if (s == "mm")   return "LENGTH";
Packit Service 7770af
    else if (s == "cm")   return "LENGTH";
Packit Service 7770af
    else if (s == "in")   return "LENGTH";
Packit Service 7770af
    // angle units
Packit Service 7770af
    else if (s == "deg")  return "ANGLE";
Packit Service 7770af
    else if (s == "grad") return "ANGLE";
Packit Service 7770af
    else if (s == "rad")  return "ANGLE";
Packit Service 7770af
    else if (s == "turn") return "ANGLE";
Packit Service 7770af
    // time units
Packit Service 7770af
    else if (s == "s")    return "TIME";
Packit Service 7770af
    else if (s == "ms")   return "TIME";
Packit Service 7770af
    // frequency units
Packit Service 7770af
    else if (s == "Hz")   return "FREQUENCY";
Packit Service 7770af
    else if (s == "kHz")  return "FREQUENCY";
Packit Service 7770af
    // resolutions units
Packit Service 7770af
    else if (s == "dpi")  return "RESOLUTION";
Packit Service 7770af
    else if (s == "dpcm") return "RESOLUTION";
Packit Service 7770af
    else if (s == "dppx") return "RESOLUTION";
Packit Service 7770af
    // for unknown units
Packit Service 7770af
    return "CUSTOM:" + s;
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
  // throws incompatibleUnits exceptions
Packit Service 7770af
  double conversion_factor(const std::string& s1, const std::string& s2, bool strict)
Packit Service 7770af
  {
Packit Service 7770af
    // assert for same units
Packit Service 7770af
    if (s1 == s2) return 1;
Packit Service 7770af
    // get unit enum from string
Packit Service 7770af
    UnitType u1 = string_to_unit(s1);
Packit Service 7770af
    UnitType u2 = string_to_unit(s2);
Packit Service 7770af
    // query unit group types
Packit Service 7770af
    UnitClass t1 = get_unit_type(u1);
Packit Service 7770af
    UnitClass t2 = get_unit_type(u2);
Packit Service 7770af
    // get absolute offset
Packit Service 7770af
    // used for array acces
Packit Service 7770af
    size_t i1 = u1 - t1;
Packit Service 7770af
    size_t i2 = u2 - t2;
Packit Service 7770af
    // error if units are not of the same group
Packit Service 7770af
    // don't error for multiplication and division
Packit Service 7770af
    if (strict && t1 != t2) throw Exception::IncompatibleUnits(u1, u2);
Packit Service 7770af
    // only process known units
Packit Service 7770af
    if (u1 != UNKNOWN && u2 != UNKNOWN) {
Packit Service 7770af
      switch (t1) {
Packit Service 7770af
        case UnitClass::LENGTH:            return size_conversion_factors[i1][i2];
Packit Service 7770af
        case UnitClass::ANGLE:             return angle_conversion_factors[i1][i2];
Packit Service 7770af
        case UnitClass::TIME:              return time_conversion_factors[i1][i2];
Packit Service 7770af
        case UnitClass::FREQUENCY:         return frequency_conversion_factors[i1][i2];
Packit Service 7770af
        case UnitClass::RESOLUTION:        return resolution_conversion_factors[i1][i2];
Packit Service 7770af
        // ToDo: should we throw error here?
Packit Service 7770af
        case UnitClass::INCOMMENSURABLE:   return 0;
Packit Service 7770af
        default: break;
Packit Service 7770af
      }
Packit Service 7770af
    }
Packit Service 7770af
    // fallback
Packit Service 7770af
    return 0;
Packit Service 7770af
  }
Packit Service 7770af
Packit Service 7770af
}