| 17 */ |
17 */ |
| 18 |
18 |
| 19 #include <QPixmap> |
19 #include <QPixmap> |
| 20 #include "model.h" |
20 #include "model.h" |
| 21 |
21 |
| |
22 constexpr unsigned int gcd(unsigned int a, unsigned int b) |
| |
23 { |
| |
24 while (a != b) { |
| |
25 if (b > a) { |
| |
26 b -= a; |
| |
27 } |
| |
28 else if (a > b) { |
| |
29 a -= b; |
| |
30 } |
| |
31 } |
| |
32 return a; |
| |
33 } |
| |
34 |
| |
35 static_assert(gcd(16, 15) == 1); |
| |
36 static_assert(gcd(16, 4) == 4); |
| |
37 static_assert(gcd(272, 192) == 16); |
| |
38 |
| |
39 static constexpr const char* circularPrimitiveTypeString(const CircularPrimitive& circ) |
| |
40 { |
| |
41 switch (circ.type) { |
| |
42 case CircularPrimitive::Circle: |
| |
43 return "edge"; |
| |
44 case CircularPrimitive::Disc: |
| |
45 return "disc"; |
| |
46 case CircularPrimitive::Cylinder: |
| |
47 return "cyli"; |
| |
48 case CircularPrimitive::CylinderOpen: |
| |
49 return "cylo"; |
| |
50 case CircularPrimitive::CylinderClosed: |
| |
51 return "cylc"; |
| |
52 case CircularPrimitive::DiscNegative: |
| |
53 return "ndis"; |
| |
54 case CircularPrimitive::Chord: |
| |
55 return "chrd"; |
| |
56 } |
| |
57 return ""; |
| |
58 } |
| |
59 |
| |
60 static QString circularPrimitiveFilePath(const CircularPrimitive& circ) |
| |
61 { |
| |
62 QString result; |
| |
63 if (circ.fraction.divisions != 16) { |
| |
64 result += QString::number(circ.fraction.divisions) + QStringLiteral("\\"); |
| |
65 } |
| |
66 const int factor = gcd(circ.fraction.segments, circ.fraction.divisions); |
| |
67 int num = circ.fraction.segments / factor; |
| |
68 int denom = circ.fraction.divisions / factor; |
| |
69 if (denom < 4) { |
| |
70 num *= 4 / denom; |
| |
71 denom = 4; |
| |
72 } |
| |
73 result += QStringLiteral("%1-%2").arg(num).arg(denom); |
| |
74 result += QString::fromLatin1(circularPrimitiveTypeString(circ)); |
| |
75 result += QStringLiteral(".dat"); |
| |
76 return result; |
| |
77 } |
| |
78 |
| 22 static const char* iconPathForElement(const ModelElement& element) |
79 static const char* iconPathForElement(const ModelElement& element) |
| 23 { |
80 { |
| 24 return std::visit(overloaded{ |
81 return std::visit(overloaded{ |
| 25 [](const Colored<SubfileReference>&) { |
82 [](const Colored<SubfileReference>&) { |
| 26 return ":/icons/linetype-subfile.png"; |
83 return ":/icons/linetype-subfile.png"; |
| 34 [](const Colored<Quadrilateral>&) { |
91 [](const Colored<Quadrilateral>&) { |
| 35 return ":/icons/linetype-quadrilateral.png"; |
92 return ":/icons/linetype-quadrilateral.png"; |
| 36 }, |
93 }, |
| 37 [](const Colored<ConditionalEdge>&) { |
94 [](const Colored<ConditionalEdge>&) { |
| 38 return ":/icons/linetype-conditionaledge.png"; |
95 return ":/icons/linetype-conditionaledge.png"; |
| |
96 }, |
| |
97 [](const Colored<CircularPrimitive>&) { |
| |
98 return ":/icons/linetype-circularprimitive.png"; |
| 39 }, |
99 }, |
| 40 [](const Comment&) { |
100 [](const Comment&) { |
| 41 return ":/icons/chatbubble-ellipses-outline.png"; |
101 return ":/icons/chatbubble-ellipses-outline.png"; |
| 42 }, |
102 }, |
| 43 [](const Empty&) { |
103 [](const Empty&) { |
| 99 .arg(cedge.color.index) |
159 .arg(cedge.color.index) |
| 100 .arg(vertexToString(cedge.p1)) |
160 .arg(vertexToString(cedge.p1)) |
| 101 .arg(vertexToString(cedge.p2)) |
161 .arg(vertexToString(cedge.p2)) |
| 102 .arg(vertexToString(cedge.c1)) |
162 .arg(vertexToString(cedge.c1)) |
| 103 .arg(vertexToString(cedge.c2)); |
163 .arg(vertexToString(cedge.c2)); |
| |
164 }, |
| |
165 [](const Colored<CircularPrimitive>& circ) { |
| |
166 return QStringLiteral("1 %1 %2 %3") |
| |
167 .arg(circ.color.index) |
| |
168 .arg(transformToString(circ.transformation)) |
| |
169 .arg(circularPrimitiveFilePath(circ)); |
| 104 }, |
170 }, |
| 105 [](const Comment& comment) { |
171 [](const Comment& comment) { |
| 106 return "0 " + comment.text; |
172 return "0 " + comment.text; |
| 107 }, |
173 }, |
| 108 [](const Empty&) { |
174 [](const Empty&) { |