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&) { |