src/document.cpp

changeset 232
8efa3a33172e
parent 228
948867719906
child 244
065db0753f05
equal deleted inserted replaced
231:a9bf6bab5ea2 232:8efa3a33172e
21 #include "algorithm/earcut.h" 21 #include "algorithm/earcut.h"
22 #include "document.h" 22 #include "document.h"
23 #include "model.h" 23 #include "model.h"
24 #include "ui/objecteditor.h" 24 #include "ui/objecteditor.h"
25 #include "gl/partrenderer.h" 25 #include "gl/partrenderer.h"
26 #include "circularprimitive.h"
26 27
27 // Make mapbox::earcut work with glm::vec3 28 // Make mapbox::earcut work with glm::vec3
28 namespace mapbox { 29 namespace mapbox {
29 namespace util { 30 namespace util {
30 template<> struct nth<0, glm::vec3> 31 template<> struct nth<0, glm::vec3>
59 this->gridPlane = planeFromTriangle({ 60 this->gridPlane = planeFromTriangle({
60 this->gridMatrix * glm::vec4{0, 0, 0, 1}, 61 this->gridMatrix * glm::vec4{0, 0, 0, 1},
61 this->gridMatrix * glm::vec4{1, 0, 0, 1}, 62 this->gridMatrix * glm::vec4{1, 0, 0, 1},
62 this->gridMatrix * glm::vec4{0, 1, 0, 1}, 63 this->gridMatrix * glm::vec4{0, 1, 0, 1},
63 }); 64 });
65 }
66
67 void EditTools::setCircleToolOptions(const CircleToolOptions& options)
68 {
69 this->circleToolOptions = options;
64 } 70 }
65 71
66 void EditTools::mvpMatrixChanged(const glm::mat4& matrix) 72 void EditTools::mvpMatrixChanged(const glm::mat4& matrix)
67 { 73 {
68 this->mvpMatrix = matrix; 74 this->mvpMatrix = matrix;
136 const PartRenderer* renderer) 142 const PartRenderer* renderer)
137 { 143 {
138 painter->drawPolygon(QPolygonF{convertWorldPointsToScreenPoints(points, renderer)}); 144 painter->drawPolygon(QPolygonF{convertWorldPointsToScreenPoints(points, renderer)});
139 } 145 }
140 146
141 static opt<std::vector<glm::vec3>> modelActionPoints(const ModelAction& action) 147 static std::vector<std::vector<glm::vec3>> modelActionPoints(const ModelAction& action)
142 { 148 {
143 opt<std::vector<glm::vec3>> result; 149 std::vector<std::vector<glm::vec3>> result;
144 if (const AppendToModel* append = std::get_if<AppendToModel>(&action)) { 150 if (const AppendToModel* append = std::get_if<AppendToModel>(&action)) {
145 const ModelElement& newElement = append->newElement; 151 const ModelElement& newElement = append->newElement;
146 if (const LineSegment* seg = std::get_if<Colored<LineSegment>>(&newElement)) { 152 if (const LineSegment* seg = std::get_if<Colored<LineSegment>>(&newElement)) {
147 result = {seg->p1, seg->p2}; 153 result.push_back({seg->p1, seg->p2});
148 } 154 }
149 else if (const Triangle* tri = std::get_if<Colored<Triangle>>(&newElement)) { 155 else if (const Triangle* tri = std::get_if<Colored<Triangle>>(&newElement)) {
150 result = {tri->p1, tri->p2, tri->p3}; 156 result.push_back({tri->p1, tri->p2, tri->p3});
151 } 157 }
152 else if (const Quadrilateral* quad = std::get_if<Colored<Quadrilateral>>(&newElement)) { 158 else if (const Quadrilateral* quad = std::get_if<Colored<Quadrilateral>>(&newElement)) {
153 result = {quad->p1, quad->p2, quad->p3, quad->p4}; 159 result.push_back({quad->p1, quad->p2, quad->p3, quad->p4});
160 }
161 else if (const CircularPrimitive* circ = std::get_if<Colored<CircularPrimitive>>(&newElement)) {
162 rasterize(*circ, [&](const ModelElement& element){
163 const auto& subpoints = modelActionPoints(AppendToModel{element});
164 std::copy(subpoints.begin(), subpoints.end(), std::back_inserter(result));
165 });
154 } 166 }
155 } 167 }
156 return result; 168 return result;
157 } 169 }
158 170
197 painter->drawEllipse(pos, 5, 5); 209 painter->drawEllipse(pos, 5, 5);
198 painter->drawText(pos + QPointF{5, 5}, vectorToString(*this->worldPosition)); 210 painter->drawText(pos + QPointF{5, 5}, vectorToString(*this->worldPosition));
199 } 211 }
200 } 212 }
201 213
214 const std::vector<ModelAction> EditTools::modelActions() const
215 {
216 switch(this->mode) {
217 case SelectMode:
218 return {};
219 case DrawMode:
220 return drawModeActions();
221 case CircleMode:
222 return circleModeActions();
223 }
224 }
225
202 void EditTools::renderPreview(QPainter* painter, const void* pensptr) 226 void EditTools::renderPreview(QPainter* painter, const void* pensptr)
203 { 227 {
204 const Pens& pens = *reinterpret_cast<const Pens*>(pensptr); 228 const Pens& pens = *reinterpret_cast<const Pens*>(pensptr);
205 painter->setPen(pens.polygonPen); 229 painter->setPen(pens.polygonPen);
206 for (const ModelAction& action : this->actions()) { 230 for (const ModelAction& action : this->modelActions()) {
207 const std::vector<glm::vec3> points = modelActionPoints(action).value_or(std::vector<glm::vec3>{}); 231 for (const std::vector<glm::vec3>& points : modelActionPoints(action)) {
208 if (points.size() == 2) { 232 if (points.size() == 2) {
209 drawWorldPolyline(painter, points, renderer); 233 drawWorldPolyline(painter, points, renderer);
210 }
211 else {
212 if (worldPolygonWinding(points, this->renderer) == Winding::Clockwise) {
213 painter->setBrush(pens.greenPolygonBrush);
214 } 234 }
215 else { 235 else {
216 painter->setBrush(pens.redPolygonBrush); 236 if (worldPolygonWinding(points, this->renderer) == Winding::Clockwise) {
217 } 237 painter->setBrush(pens.greenPolygonBrush);
218 drawWorldPolygon(painter, points, this->renderer); 238 }
239 else {
240 painter->setBrush(pens.redPolygonBrush);
241 }
242 drawWorldPolygon(painter, points, this->renderer);
243 }
219 } 244 }
220 } 245 }
221 painter->setBrush(pens.pointBrush); 246 painter->setBrush(pens.pointBrush);
222 painter->setPen(pens.pointPen); 247 painter->setPen(pens.pointPen);
223 for (const glm::vec3& point : this->polygon) { 248 for (const glm::vec3& point : this->polygon) {
266 } 291 }
267 else { 292 else {
268 this->polygon.push_back(*this->worldPosition); 293 this->polygon.push_back(*this->worldPosition);
269 } 294 }
270 } 295 }
271 else if (true
272 and event->button() == Qt::RightButton
273 and this->polygon.size() > 1
274 ) {
275 this->removeLastPoint();
276 }
277 break; 296 break;
278 } 297 case CircleMode:
279 } 298 if (event->button() == Qt::LeftButton and this->worldPosition.has_value()) {
280 299 if (this->polygon.size() == 2) {
281 constexpr float distancesquared(const glm::vec3& p1, const glm::vec3& p2) 300 this->closeShape();
282 { 301 }
283 const float dx = p2.x - p1.x; 302 else {
284 const float dy = p2.y - p1.y; 303 this->polygon.push_back(*this->worldPosition);
285 const float dz = p2.z - p1.z; 304 }
286 return (dx * dx) + (dy * dy) + (dz * dz); 305 }
287 } 306 break;
288 307 }
289 inline float area(const Quadrilateral& q) 308 if (event->button() == Qt::RightButton and this->polygon.size() > 1) {
290 { 309 this->removeLastPoint();
291 return 0.5 * ( 310 }
292 glm::length(glm::cross(q.p2 - q.p1, q.p3 - q.p1)) +
293 glm::length(glm::cross(q.p3 - q.p2, q.p4 - q.p2))
294 );
295 }
296
297 inline float energy(const Quadrilateral& q)
298 {
299 const float L2 = distancesquared(q.p1, q.p2)
300 + distancesquared(q.p2, q.p3)
301 + distancesquared(q.p3, q.p4)
302 + distancesquared(q.p4, q.p1);
303 return 1 - 6.928203230275509 * area(q) / L2;
304 } 311 }
305 312
306 struct MergedTriangles 313 struct MergedTriangles
307 { 314 {
308 std::vector<Quadrilateral> quadrilaterals; 315 std::vector<Quadrilateral> quadrilaterals;
363 } 370 }
364 } 371 }
365 return result; 372 return result;
366 } 373 }
367 374
368 const std::vector<ModelAction> EditTools::actions() const 375
376 const std::vector<ModelAction> EditTools::circleModeActions() const
377 {
378 std::vector<ModelAction> result;
379 if (this->numpoints == 2) {
380 const glm::vec3 x = polygon[1] - polygon[0];
381 glm::mat4 transform{
382 glm::vec4{x, 0},
383 this->gridMatrix[2],
384 glm::vec4{glm::cross(glm::vec3{-this->gridMatrix[2]}, x), 0},
385 glm::vec4{this->polygon[0], 1},
386 };
387 Colored<CircularPrimitive> circ{
388 CircularPrimitive{
389 .type = this->circleToolOptions.type,
390 .fraction = this->circleToolOptions.fraction,
391 .transformation = transform,
392 },
393 MAIN_COLOR
394 };
395 result.push_back(AppendToModel{.newElement = circ});
396 }
397 return result;
398 }
399
400 const std::vector<ModelAction> EditTools::drawModeActions() const
369 { 401 {
370 std::vector<ModelAction> result; 402 std::vector<ModelAction> result;
371 if (this->numpoints == 2) { 403 if (this->numpoints == 2) {
372 result.push_back(AppendToModel{ 404 result.push_back(AppendToModel{
373 .newElement = Colored<LineSegment>{ 405 .newElement = Colored<LineSegment>{
413 return result; 445 return result;
414 } 446 }
415 447
416 void EditTools::closeShape() 448 void EditTools::closeShape()
417 { 449 {
418 for (const ModelAction& action : this->actions()) { 450 for (const ModelAction& action : this->modelActions()) {
419 Q_EMIT this->modelAction(action); 451 Q_EMIT this->modelAction(action);
420 } 452 }
421 this->polygon.clear(); 453 this->polygon.clear();
422 this->polygon.push_back(this->worldPosition.value_or(glm::vec3{0, 0, 0})); 454 this->polygon.push_back(this->worldPosition.value_or(glm::vec3{0, 0, 0}));
423 } 455 }

mercurial