38 constexpr bool n_xor(bool a, Args&&... rest) |
39 constexpr bool n_xor(bool a, Args&&... rest) |
39 { |
40 { |
40 return a xor n_xor(rest...); |
41 return a xor n_xor(rest...); |
41 } |
42 } |
42 |
43 |
|
44 namespace { |
|
45 struct GetPolygonsContext |
|
46 { |
|
47 bool invertnext = false; |
|
48 ModelId modelId; |
|
49 class DocumentManager* documents; |
|
50 }; |
|
51 } |
|
52 |
43 template<typename Fn, typename Fn2> |
53 template<typename Fn, typename Fn2> |
44 static void inlineSubfileReference( |
54 static void inlineSubfileReference( |
45 const PolygonCache::vector_type& polygons, |
55 const PolygonCache::vector_type& polygons, |
46 const Colored<SubfileReference>& ref, |
56 const Colored<SubfileReference>& ref, |
|
57 GetPolygonsContext* context, |
47 Fn&& add, |
58 Fn&& add, |
48 Fn2&& reserve) |
59 Fn2&& reserve) |
49 { |
60 { |
50 const bool needInverting = 0 |
61 const bool needInverting = 0 |
51 ^ (glm::determinant(ref.transformation) < 0) |
62 ^ (glm::determinant(ref.transformation) < 0) |
52 ^ (ref.inverted); |
63 ^ (context->invertnext); |
53 reserve(polygons.size()); |
64 reserve(polygons.size()); |
54 for (const PolygonElement& cacheElement : polygons) { |
65 for (const PolygonElement& cacheElement : polygons) { |
55 PolygonElement polygon = transformed(cacheElement, ref.transformation); |
66 PolygonElement polygon = transformed(cacheElement, ref.transformation); |
56 if (needInverting) { |
67 if (needInverting) { |
57 gl::invert(polygon); |
68 gl::invert(polygon); |
61 } |
72 } |
62 add(polygon); |
73 add(polygon); |
63 } |
74 } |
64 } |
75 } |
65 |
76 |
66 Model* findDependency(const SubfileReference& ref, GetPolygonsContext* context) |
77 static Model* findDependency(const SubfileReference& ref, GetPolygonsContext* context) |
67 { |
78 { |
68 return context->documents->findDependencyByName(context->modelId, ref.name); |
79 return context->documents->findDependencyByName(context->modelId, ref.name); |
69 } |
80 } |
70 |
81 |
71 template<typename Fn, typename Fn2> |
82 template<typename Fn, typename Fn2> |
72 static void collectPolygons( |
83 static void collectPolygons( |
73 const ModelElement& element, |
84 const ParsedLine& element, |
74 Winding& winding, |
85 Winding& winding, |
75 GetPolygonsContext* context, |
86 GetPolygonsContext* context, |
76 Fn&& add, |
87 Fn&& add, |
77 Fn2&& reserve) |
88 Fn2&& reserve) |
78 { |
89 { |
|
90 bool foundinvertnext = false; |
79 std::visit<void>(overloaded{ |
91 std::visit<void>(overloaded{ |
80 [&](const Colored<LineSegment>& edge) { |
92 [&](const LineType0& line0) { |
81 add({edge, edge.color}); |
93 const QString text = line0.value.text.simplified(); |
|
94 if (text == QStringLiteral("BFC INVERTNEXT")) { |
|
95 context->invertnext = true; |
|
96 foundinvertnext = true; |
|
97 } |
|
98 else if (text == QStringLiteral("BFC CERTIFY CW")) { |
|
99 winding = Clockwise; |
|
100 } |
|
101 else if (text == QStringLiteral("BFC CERTIFY CCW")) { |
|
102 winding = Anticlockwise; |
|
103 } |
|
104 else if (text == QStringLiteral("BFC NOCERTIFY")) { |
|
105 winding = NoWinding; |
|
106 } |
82 }, |
107 }, |
83 [&](const Colored<Triangle>& triangle) { |
108 [&](const LineType2& line2) { |
84 add({triangle, triangle.color}); |
109 add({line2.value, line2.value.color}); |
85 }, |
110 }, |
86 [&](const Colored<Quadrilateral>& quad) { |
111 [&](const LineType3& line3) { |
87 add({quad, quad.color}); |
112 add({line3.value, line3.value.color}); |
88 }, |
113 }, |
89 [&](const Colored<ConditionalEdge>& cedge) { |
114 [&](const LineType4& line4) { |
90 add({cedge, cedge.color}); |
115 add({line4.value, line4.value.color}); |
91 }, |
116 }, |
92 [&add, context, &reserve](const Colored<SubfileReference>& ref) { |
117 [&](const LineType5& line5) { |
93 Model* const dependency = findDependency(ref, context); |
118 add({line5.value, line5.value.color}); |
|
119 }, |
|
120 [&add, context, &reserve](const LineType1& line1) { |
|
121 Model* const dependency = findDependency(line1.value, context); |
94 if (PolygonCache* cache = (dependency != nullptr) |
122 if (PolygonCache* cache = (dependency != nullptr) |
95 ? findPolygonCacheForModel(dependency, context->documents) |
123 ? findPolygonCacheForModel(dependency, context->documents) |
96 : nullptr |
124 : nullptr |
97 ) { |
125 ) { |
98 recacheIfNeeded(cache, dependency, context->documents); |
126 recacheIfNeeded(cache, dependency, context->documents); |
99 inlineSubfileReference(cache->polygons, ref, add, reserve); |
127 inlineSubfileReference(cache->polygons, line1.value, context, add, reserve); |
100 } |
128 } |
101 }, |
129 }, |
|
130 #if 0 |
102 [&add](const Colored<CircularPrimitive>& circ) { |
131 [&add](const Colored<CircularPrimitive>& circ) { |
103 rasterize(circ, [&](const PlainPolygonElement& polygon, ColorIndex color){ |
132 rasterize(circ, [&](const PlainPolygonElement& polygon, ColorIndex color){ |
104 if (color == MAIN_COLOR) { |
133 if (color == MAIN_COLOR) { |
105 color = circ.color; |
134 color = circ.color; |
106 } |
135 } |
107 add(PolygonElement{polygon, color}); |
136 add(PolygonElement{polygon, color}); |
108 }); |
137 }); |
109 }, |
138 }, |
110 [&winding](const Comment& comment) { |
139 #endif |
111 if (comment.text == QStringLiteral("BFC CERTIFY CW")) { |
|
112 winding = Clockwise; |
|
113 } |
|
114 else if (comment.text == QStringLiteral("BFC CERTIFY CCW")) { |
|
115 winding = Anticlockwise; |
|
116 } |
|
117 else if (comment.text == QStringLiteral("BFC NOCERTIFY")) { |
|
118 winding = NoWinding; |
|
119 } |
|
120 }, |
|
121 [](const ModelElement&) {} |
|
122 }, element); |
140 }, element); |
|
141 if (not foundinvertnext) { |
|
142 context->invertnext = false; |
|
143 } |
123 } |
144 } |
124 |
145 |
125 static std::vector<WithId<PolygonElement>> inlinePolygons( |
146 static std::vector<WithId<PolygonElement>> inlinePolygons( |
126 const Model* model, |
147 const Model* model, |
127 GetPolygonsContext* context) |
148 GetPolygonsContext* context) |
128 { |
149 { |
129 Winding winding = NoWinding; |
150 Winding winding = NoWinding; |
130 std::vector<WithId<PolygonElement>> result; |
151 std::vector<WithId<PolygonElement>> result; |
131 for (std::size_t i = 0; i < model->size(); i += 1) |
152 int i = 0; |
132 { |
153 const auto add = [&result, winding, i](const PolygonElement& poly){ |
133 const ModelElement& element = (*model)[i]; |
154 result.push_back({poly, i}); |
134 const ElementId id = model->idAt(i); |
155 if (winding == Winding::Clockwise) { |
135 collectPolygons(element, winding, context, |
156 gl::invert(result.back()); |
136 [&result, winding, id](const PolygonElement& poly){ |
157 } |
137 result.push_back({poly, id}); |
158 }; |
138 if (winding == Winding::Clockwise) { |
159 const auto reserve = [&result](std::size_t incomingsize){ |
139 gl::invert(result.back()); |
160 reserveMore(result, incomingsize); |
140 } |
161 }; |
141 }, [&result](std::size_t incomingsize){ |
162 for (const QString& line : model->toPlainText().split("\n")) { |
142 reserveMore(result, incomingsize); |
163 const opt<ParsedLine> parsedline = parse(line); |
143 }); |
164 if (parsedline.has_value()) { |
|
165 collectPolygons(*parsedline, winding, context, add, reserve); |
|
166 } |
|
167 ++i; |
144 } |
168 } |
145 return result; |
169 return result; |
146 } |
170 } |
147 |
171 |
148 void recacheIfNeeded(PolygonCache *cache, Model *model, DocumentManager *documents) |
172 void recacheIfNeeded(PolygonCache *cache, Model *model, DocumentManager *documents) |