|
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 |
}
|