7 /* the conversion matrix can be readed the following way */
8 /* if you go down, the factor is for the numerator (multiply) */
9 /* if you go right, the factor is for the denominator (divide) */
10 /* and yes, we actually use both, not sure why, but why not!? */
12 const double size_conversion_factors[6][6] =
14 /* in cm pc mm pt px */
15 /* in */ { 1, 2.54, 6, 25.4, 72, 96, },
16 /* cm */ { 1.0/2.54, 1, 6.0/2.54, 10, 72.0/2.54, 96.0/2.54 },
17 /* pc */ { 1.0/6.0, 2.54/6.0, 1, 25.4/6.0, 72.0/6.0, 96.0/6.0 },
18 /* mm */ { 1.0/25.4, 1.0/10.0, 6.0/25.4, 1, 72.0/25.4, 96.0/25.4 },
19 /* pt */ { 1.0/72.0, 2.54/72.0, 6.0/72.0, 25.4/72.0, 1, 96.0/72.0 },
20 /* px */ { 1.0/96.0, 2.54/96.0, 6.0/96.0, 25.4/96.0, 72.0/96.0, 1, }
23 const double angle_conversion_factors[4][4] =
25 /* deg grad rad turn */
26 /* deg */ { 1, 40.0/36.0, PI/180.0, 1.0/360.0 },
27 /* grad */ { 36.0/40.0, 1, PI/200.0, 1.0/400.0 },
28 /* rad */ { 180.0/PI, 200.0/PI, 1, 0.5/PI },
29 /* turn */ { 360.0, 400.0, 2.0*PI, 1 }
32 const double time_conversion_factors[2][2] =
35 /* s */ { 1, 1000.0 },
36 /* ms */ { 1/1000.0, 1 }
38 const double frequency_conversion_factors[2][2] =
41 /* Hz */ { 1, 1/1000.0 },
42 /* kHz */ { 1000.0, 1 }
44 const double resolution_conversion_factors[3][3] =
47 /* dpi */ { 1, 1/2.54, 1/96.0 },
48 /* dpcm */ { 2.54, 1, 2.54/96 },
49 /* dppx */ { 96, 96/2.54, 1 }
52 UnitClass get_unit_type(UnitType unit)
54 switch (unit & 0xFF00)
56 case UnitClass::LENGTH: return UnitClass::LENGTH; break;
57 case UnitClass::ANGLE: return UnitClass::ANGLE; break;
58 case UnitClass::TIME: return UnitClass::TIME; break;
59 case UnitClass::FREQUENCY: return UnitClass::FREQUENCY; break;
60 case UnitClass::RESOLUTION: return UnitClass::RESOLUTION; break;
61 default: return UnitClass::INCOMMENSURABLE; break;
65 std::string get_unit_class(UnitType unit)
67 switch (unit & 0xFF00)
69 case UnitClass::LENGTH: return "LENGTH"; break;
70 case UnitClass::ANGLE: return "ANGLE"; break;
71 case UnitClass::TIME: return "TIME"; break;
72 case UnitClass::FREQUENCY: return "FREQUENCY"; break;
73 case UnitClass::RESOLUTION: return "RESOLUTION"; break;
74 default: return "INCOMMENSURABLE"; break;
78 UnitType string_to_unit(const std::string& s)
81 if (s == "px") return UnitType::PX;
82 else if (s == "pt") return UnitType::PT;
83 else if (s == "pc") return UnitType::PC;
84 else if (s == "mm") return UnitType::MM;
85 else if (s == "cm") return UnitType::CM;
86 else if (s == "in") return UnitType::IN;
88 else if (s == "deg") return UnitType::DEG;
89 else if (s == "grad") return UnitType::GRAD;
90 else if (s == "rad") return UnitType::RAD;
91 else if (s == "turn") return UnitType::TURN;
93 else if (s == "s") return UnitType::SEC;
94 else if (s == "ms") return UnitType::MSEC;
96 else if (s == "Hz") return UnitType::HERTZ;
97 else if (s == "kHz") return UnitType::KHERTZ;
99 else if (s == "dpi") return UnitType::DPI;
100 else if (s == "dpcm") return UnitType::DPCM;
101 else if (s == "dppx") return UnitType::DPPX;
103 else return UnitType::UNKNOWN;
106 const char* unit_to_string(UnitType unit)
110 case UnitType::PX: return "px"; break;
111 case UnitType::PT: return "pt"; break;
112 case UnitType::PC: return "pc"; break;
113 case UnitType::MM: return "mm"; break;
114 case UnitType::CM: return "cm"; break;
115 case UnitType::IN: return "in"; break;
117 case UnitType::DEG: return "deg"; break;
118 case UnitType::GRAD: return "grad"; break;
119 case UnitType::RAD: return "rad"; break;
120 case UnitType::TURN: return "turn"; break;
122 case UnitType::SEC: return "s"; break;
123 case UnitType::MSEC: return "ms"; break;
125 case UnitType::HERTZ: return "Hz"; break;
126 case UnitType::KHERTZ: return "kHz"; break;
128 case UnitType::DPI: return "dpi"; break;
129 case UnitType::DPCM: return "dpcm"; break;
130 case UnitType::DPPX: return "dppx"; break;
132 default: return ""; break;
136 std::string unit_to_class(const std::string& s)
138 if (s == "px") return "LENGTH";
139 else if (s == "pt") return "LENGTH";
140 else if (s == "pc") return "LENGTH";
141 else if (s == "mm") return "LENGTH";
142 else if (s == "cm") return "LENGTH";
143 else if (s == "in") return "LENGTH";
145 else if (s == "deg") return "ANGLE";
146 else if (s == "grad") return "ANGLE";
147 else if (s == "rad") return "ANGLE";
148 else if (s == "turn") return "ANGLE";
150 else if (s == "s") return "TIME";
151 else if (s == "ms") return "TIME";
153 else if (s == "Hz") return "FREQUENCY";
154 else if (s == "kHz") return "FREQUENCY";
156 else if (s == "dpi") return "RESOLUTION";
157 else if (s == "dpcm") return "RESOLUTION";
158 else if (s == "dppx") return "RESOLUTION";
160 return "CUSTOM:" + s;
163 // throws incompatibleUnits exceptions
164 double conversion_factor(const std::string& s1, const std::string& s2, bool strict)
166 // assert for same units
167 if (s1 == s2) return 1;
168 // get unit enum from string
169 UnitType u1 = string_to_unit(s1);
170 UnitType u2 = string_to_unit(s2);
171 // query unit group types
172 UnitClass t1 = get_unit_type(u1);
173 UnitClass t2 = get_unit_type(u2);
174 // get absolute offset
175 // used for array acces
178 // error if units are not of the same group
179 // don't error for multiplication and division
180 if (strict && t1 != t2) throw incompatibleUnits(u1, u2);
181 // only process known units
182 if (u1 != UNKNOWN && u2 != UNKNOWN) {
184 case UnitClass::LENGTH: return size_conversion_factors[i1][i2]; break;
185 case UnitClass::ANGLE: return angle_conversion_factors[i1][i2]; break;
186 case UnitClass::TIME: return time_conversion_factors[i1][i2]; break;
187 case UnitClass::FREQUENCY: return frequency_conversion_factors[i1][i2]; break;
188 case UnitClass::RESOLUTION: return resolution_conversion_factors[i1][i2]; break;
189 // ToDo: should we throw error here?
190 case UnitClass::INCOMMENSURABLE: return 0; break;