|
| 1 | +#include <stdexcept> |
1 | 2 | #include "units.hpp"
|
2 | 3 |
|
3 |
| -#define PI 3.14159265358979323846 |
4 |
| - |
5 | 4 | namespace Sass {
|
6 | 5 |
|
7 |
| - double conversion_factors[10][10] = { |
8 |
| - /* in cm pc mm pt px deg grad rad turn */ |
9 |
| - /* in */ { 1, 2.54, 6, 25.4, 72, 96, 1, 1, 1, 1 }, |
10 |
| - /* cm */ { 1.0/2.54, 1, 6.0/2.54, 10, 72.0/2.54, 96.0/2.54, 1, 1, 1, 1 }, |
11 |
| - /* pc */ { 1.0/6.0, 2.54/6.0, 1, 25.4/6.0, 72.0/6.0, 96.0/6.0, 1, 1, 1, 1 }, |
12 |
| - /* mm */ { 1.0/25.4, 1.0/10.0, 6.0/25.4, 1, 72.0/25.4, 96.0/25.4, 1, 1, 1, 1 }, |
13 |
| - /* pt */ { 1.0/72.0, 2.54/72.0, 6.0/72.0, 25.4/72.0, 1, 96.0/72.0, 1, 1, 1, 1 }, |
14 |
| - /* px */ { 1.0/96.0, 2.54/96.0, 6.0/96.0, 25.4/96.0, 72.0/96.0, 1, 1, 1, 1, 1 }, |
15 |
| - /* deg */ { 1 , 1 , 1 , 1 , 1 , 1, 1, 40.0/36.0, PI/180.0, 1.0/360.0 }, |
16 |
| - /* grad */ { 1 , 1 , 1 , 1 , 1 , 1, 36.0/40.0, 1, PI/200.0, 1.0/400.0 }, |
17 |
| - /* rad */ { 1 , 1 , 1 , 1 , 1 , 1, 180.0/PI, 200.0/PI, 1, PI/2.0 }, |
18 |
| - /* turn */ { 1 , 1 , 1 , 1 , 1 , 1, 360.0/1.0, 400.0/1.0, 2.0*PI, 1 } |
| 6 | + /* the conversion matrix can be readed the following way */ |
| 7 | + /* if you go down, the factor is for the numerator (multiply) */ |
| 8 | + /* if you go right, the factor is for the denominator (divide) */ |
| 9 | + /* and yes, we actually use both, not sure why, but why not!? */ |
| 10 | + |
| 11 | + const double size_conversion_factors[6][6] = |
| 12 | + { |
| 13 | + /* in cm pc mm pt px */ |
| 14 | + /* in */ { 1, 2.54, 6, 25.4, 72, 96, }, |
| 15 | + /* cm */ { 1.0/2.54, 1, 6.0/2.54, 10, 72.0/2.54, 96.0/2.54 }, |
| 16 | + /* pc */ { 1.0/6.0, 2.54/6.0, 1, 25.4/6.0, 72.0/6.0, 96.0/6.0 }, |
| 17 | + /* mm */ { 1.0/25.4, 1.0/10.0, 6.0/25.4, 1, 72.0/25.4, 96.0/25.4 }, |
| 18 | + /* pt */ { 1.0/72.0, 2.54/72.0, 6.0/72.0, 25.4/72.0, 1, 96.0/72.0 }, |
| 19 | + /* px */ { 1.0/96.0, 2.54/96.0, 6.0/96.0, 25.4/96.0, 72.0/96.0, 1, } |
19 | 20 | };
|
20 | 21 |
|
21 |
| - Unit string_to_unit(const string& s) |
| 22 | + const double angle_conversion_factors[4][4] = |
22 | 23 | {
|
23 |
| - if (s == "in") return IN; |
24 |
| - else if (s == "cm") return CM; |
| 24 | + /* deg grad rad turn */ |
| 25 | + /* deg */ { 1, 40.0/36.0, PI/180.0, 1.0/360.0 }, |
| 26 | + /* grad */ { 36.0/40.0, 1, PI/200.0, 1.0/400.0 }, |
| 27 | + /* rad */ { 180.0/PI, 200.0/PI, 1, 0.5/PI }, |
| 28 | + /* turn */ { 360.0, 400.0, 2.0*PI, 1 } |
| 29 | + }; |
| 30 | + |
| 31 | + const double time_conversion_factors[2][2] = |
| 32 | + { |
| 33 | + /* s ms */ |
| 34 | + /* s */ { 1, 1000.0 }, |
| 35 | + /* ms */ { 1/1000.0, 1 } |
| 36 | + }; |
| 37 | + const double frequency_conversion_factors[2][2] = |
| 38 | + { |
| 39 | + /* Hz kHz */ |
| 40 | + /* Hz */ { 1, 1/1000.0 }, |
| 41 | + /* kHz */ { 1000.0, 1 } |
| 42 | + }; |
| 43 | + const double resolution_conversion_factors[3][3] = |
| 44 | + { |
| 45 | + /* dpi dpcm dppx */ |
| 46 | + /* dpi */ { 1, 2.54, 96 }, |
| 47 | + /* dpcm */ { 1/2.54, 1, 96/2.54 }, |
| 48 | + /* dppx */ { 1/96.0, 2.54/96, 1 } |
| 49 | + }; |
| 50 | + |
| 51 | + SassUnitType get_unit_type(SassUnit unit) |
| 52 | + { |
| 53 | + switch (unit & 0xFF00) |
| 54 | + { |
| 55 | + case SIZE: return SIZE; break; |
| 56 | + case ANGLE: return ANGLE; break; |
| 57 | + case TIME: return TIME; break; |
| 58 | + case FREQUENCY: return FREQUENCY; break; |
| 59 | + case RESOLUTION: return RESOLUTION; break; |
| 60 | + default: return INCOMMENSURABLE; break; |
| 61 | + } |
| 62 | + }; |
| 63 | + |
| 64 | + SassUnit string_to_unit(const string& s) |
| 65 | + { |
| 66 | + // size units |
| 67 | + if (s == "px") return PX; |
| 68 | + else if (s == "pt") return PT; |
25 | 69 | else if (s == "pc") return PC;
|
26 | 70 | else if (s == "mm") return MM;
|
27 |
| - else if (s == "pt") return PT; |
28 |
| - else if (s == "px") return PX; |
| 71 | + else if (s == "cm") return CM; |
| 72 | + else if (s == "in") return IN; |
| 73 | + // angle units |
29 | 74 | else if (s == "deg") return DEG;
|
30 | 75 | else if (s == "grad") return GRAD;
|
31 | 76 | else if (s == "rad") return RAD;
|
32 | 77 | else if (s == "turn") return TURN;
|
33 |
| - else return INCOMMENSURABLE; |
| 78 | + // time units |
| 79 | + else if (s == "s") return SEC; |
| 80 | + else if (s == "ms") return MSEC; |
| 81 | + // frequency units |
| 82 | + else if (s == "Hz") return HERTZ; |
| 83 | + else if (s == "kHz") return KHERTZ; |
| 84 | + // resolutions units |
| 85 | + else if (s == "dpi") return DPI; |
| 86 | + else if (s == "dpcm") return DPCM; |
| 87 | + else if (s == "dppx") return DPPX; |
| 88 | + // for unknown units |
| 89 | + else return UNKNOWN; |
34 | 90 | }
|
35 | 91 |
|
36 |
| - double conversion_factor(const string& s1, const string& s2) |
| 92 | + const char* unit_to_string(SassUnit unit) |
37 | 93 | {
|
38 |
| - Unit u1 = string_to_unit(s1); |
39 |
| - Unit u2 = string_to_unit(s2); |
40 |
| - double factor; |
41 |
| - if (u1 == INCOMMENSURABLE || u2 == INCOMMENSURABLE) |
42 |
| - factor = 0; |
43 |
| - else |
44 |
| - factor = conversion_factors[u1][u2]; |
45 |
| - return factor; |
| 94 | + switch (unit) { |
| 95 | + // size units |
| 96 | + case PX: return "px"; break; |
| 97 | + case PT: return "pt"; break; |
| 98 | + case PC: return "pc"; break; |
| 99 | + case MM: return "mm"; break; |
| 100 | + case CM: return "cm"; break; |
| 101 | + case IN: return "in"; break; |
| 102 | + // angle units |
| 103 | + case DEG: return "deg"; break; |
| 104 | + case GRAD: return "grad"; break; |
| 105 | + case RAD: return "rad"; break; |
| 106 | + case TURN: return "turn"; break; |
| 107 | + // time units |
| 108 | + case SEC: return "s"; break; |
| 109 | + case MSEC: return "ms"; break; |
| 110 | + // frequency units |
| 111 | + case HERTZ: return "Hz"; break; |
| 112 | + case KHERTZ: return "kHz"; break; |
| 113 | + // resolutions units |
| 114 | + case DPI: return "dpi"; break; |
| 115 | + case DPCM: return "dpcm"; break; |
| 116 | + case DPPX: return "dppx"; break; |
| 117 | + // for unknown units |
| 118 | + default: return ""; break;; |
| 119 | + } |
46 | 120 | }
|
47 | 121 |
|
48 |
| - /* not used anymore - remove? |
49 |
| - double convert(double n, const string& from, const string& to) |
| 122 | + // throws incompatibleUnits exceptions |
| 123 | + double conversion_factor(const string& s1, const string& s2) |
50 | 124 | {
|
51 |
| - double factor = conversion_factor(from, to); |
52 |
| - return factor ? factor * n : n; |
53 |
| - } */ |
| 125 | + // assert for same units |
| 126 | + if (s1 == s2) return 1; |
| 127 | + // get unit enum from string |
| 128 | + SassUnit u1 = string_to_unit(s1); |
| 129 | + SassUnit u2 = string_to_unit(s2); |
| 130 | + // query unit group types |
| 131 | + SassUnitType t1 = get_unit_type(u1); |
| 132 | + SassUnitType t2 = get_unit_type(u2); |
| 133 | + // get absolute offset |
| 134 | + // used for array acces |
| 135 | + size_t i1 = u1 - t1; |
| 136 | + size_t i2 = u2 - t2; |
| 137 | + // error if units are not of the same group |
| 138 | + if (t1 != t2) throw incompatibleUnits(u1, u2); |
| 139 | + // only process known units |
| 140 | + if (u1 != UNKNOWN && u2 != UNKNOWN) { |
| 141 | + switch (t1) { |
| 142 | + case SIZE: return size_conversion_factors[i1][i2]; break; |
| 143 | + case ANGLE: return angle_conversion_factors[i1][i2]; break; |
| 144 | + case TIME: return time_conversion_factors[i1][i2]; break; |
| 145 | + case FREQUENCY: return frequency_conversion_factors[i1][i2]; break; |
| 146 | + case RESOLUTION: return resolution_conversion_factors[i1][i2]; break; |
| 147 | + // ToDo: should we throw error here? |
| 148 | + case INCOMMENSURABLE: return 0; break; |
| 149 | + } |
| 150 | + } |
| 151 | + // fallback |
| 152 | + return 1; |
| 153 | + } |
54 | 154 |
|
55 | 155 | }
|
0 commit comments