--- a/src/document.cpp Wed Jun 15 19:47:02 2022 +0300 +++ b/src/document.cpp Mon Jun 20 02:04:51 2022 +0300 @@ -23,6 +23,7 @@ #include "model.h" #include "ui/objecteditor.h" #include "gl/partrenderer.h" +#include "circularprimitive.h" // Make mapbox::earcut work with glm::vec3 namespace mapbox { @@ -63,6 +64,11 @@ }); } +void EditTools::setCircleToolOptions(const CircleToolOptions& options) +{ + this->circleToolOptions = options; +} + void EditTools::mvpMatrixChanged(const glm::mat4& matrix) { this->mvpMatrix = matrix; @@ -138,19 +144,25 @@ painter->drawPolygon(QPolygonF{convertWorldPointsToScreenPoints(points, renderer)}); } -static opt<std::vector<glm::vec3>> modelActionPoints(const ModelAction& action) +static std::vector<std::vector<glm::vec3>> modelActionPoints(const ModelAction& action) { - opt<std::vector<glm::vec3>> result; + std::vector<std::vector<glm::vec3>> result; if (const AppendToModel* append = std::get_if<AppendToModel>(&action)) { const ModelElement& newElement = append->newElement; if (const LineSegment* seg = std::get_if<Colored<LineSegment>>(&newElement)) { - result = {seg->p1, seg->p2}; + result.push_back({seg->p1, seg->p2}); } else if (const Triangle* tri = std::get_if<Colored<Triangle>>(&newElement)) { - result = {tri->p1, tri->p2, tri->p3}; + result.push_back({tri->p1, tri->p2, tri->p3}); } else if (const Quadrilateral* quad = std::get_if<Colored<Quadrilateral>>(&newElement)) { - result = {quad->p1, quad->p2, quad->p3, quad->p4}; + result.push_back({quad->p1, quad->p2, quad->p3, quad->p4}); + } + else if (const CircularPrimitive* circ = std::get_if<Colored<CircularPrimitive>>(&newElement)) { + rasterize(*circ, [&](const ModelElement& element){ + const auto& subpoints = modelActionPoints(AppendToModel{element}); + std::copy(subpoints.begin(), subpoints.end(), std::back_inserter(result)); + }); } } return result; @@ -199,23 +211,36 @@ } } +const std::vector<ModelAction> EditTools::modelActions() const +{ + switch(this->mode) { + case SelectMode: + return {}; + case DrawMode: + return drawModeActions(); + case CircleMode: + return circleModeActions(); + } +} + void EditTools::renderPreview(QPainter* painter, const void* pensptr) { const Pens& pens = *reinterpret_cast<const Pens*>(pensptr); painter->setPen(pens.polygonPen); - for (const ModelAction& action : this->actions()) { - const std::vector<glm::vec3> points = modelActionPoints(action).value_or(std::vector<glm::vec3>{}); - if (points.size() == 2) { - drawWorldPolyline(painter, points, renderer); - } - else { - if (worldPolygonWinding(points, this->renderer) == Winding::Clockwise) { - painter->setBrush(pens.greenPolygonBrush); + for (const ModelAction& action : this->modelActions()) { + for (const std::vector<glm::vec3>& points : modelActionPoints(action)) { + if (points.size() == 2) { + drawWorldPolyline(painter, points, renderer); } else { - painter->setBrush(pens.redPolygonBrush); + if (worldPolygonWinding(points, this->renderer) == Winding::Clockwise) { + painter->setBrush(pens.greenPolygonBrush); + } + else { + painter->setBrush(pens.redPolygonBrush); + } + drawWorldPolygon(painter, points, this->renderer); } - drawWorldPolygon(painter, points, this->renderer); } } painter->setBrush(pens.pointBrush); @@ -268,39 +293,21 @@ this->polygon.push_back(*this->worldPosition); } } - else if (true - and event->button() == Qt::RightButton - and this->polygon.size() > 1 - ) { - this->removeLastPoint(); + break; + case CircleMode: + if (event->button() == Qt::LeftButton and this->worldPosition.has_value()) { + if (this->polygon.size() == 2) { + this->closeShape(); + } + else { + this->polygon.push_back(*this->worldPosition); + } } break; } -} - -constexpr float distancesquared(const glm::vec3& p1, const glm::vec3& p2) -{ - const float dx = p2.x - p1.x; - const float dy = p2.y - p1.y; - const float dz = p2.z - p1.z; - return (dx * dx) + (dy * dy) + (dz * dz); -} - -inline float area(const Quadrilateral& q) -{ - return 0.5 * ( - glm::length(glm::cross(q.p2 - q.p1, q.p3 - q.p1)) + - glm::length(glm::cross(q.p3 - q.p2, q.p4 - q.p2)) - ); -} - -inline float energy(const Quadrilateral& q) -{ - const float L2 = distancesquared(q.p1, q.p2) - + distancesquared(q.p2, q.p3) - + distancesquared(q.p3, q.p4) - + distancesquared(q.p4, q.p1); - return 1 - 6.928203230275509 * area(q) / L2; + if (event->button() == Qt::RightButton and this->polygon.size() > 1) { + this->removeLastPoint(); + } } struct MergedTriangles @@ -365,7 +372,32 @@ return result; } -const std::vector<ModelAction> EditTools::actions() const + +const std::vector<ModelAction> EditTools::circleModeActions() const +{ + std::vector<ModelAction> result; + if (this->numpoints == 2) { + const glm::vec3 x = polygon[1] - polygon[0]; + glm::mat4 transform{ + glm::vec4{x, 0}, + this->gridMatrix[2], + glm::vec4{glm::cross(glm::vec3{-this->gridMatrix[2]}, x), 0}, + glm::vec4{this->polygon[0], 1}, + }; + Colored<CircularPrimitive> circ{ + CircularPrimitive{ + .type = this->circleToolOptions.type, + .fraction = this->circleToolOptions.fraction, + .transformation = transform, + }, + MAIN_COLOR + }; + result.push_back(AppendToModel{.newElement = circ}); + } + return result; +} + +const std::vector<ModelAction> EditTools::drawModeActions() const { std::vector<ModelAction> result; if (this->numpoints == 2) { @@ -415,7 +447,7 @@ void EditTools::closeShape() { - for (const ModelAction& action : this->actions()) { + for (const ModelAction& action : this->modelActions()) { Q_EMIT this->modelAction(action); } this->polygon.clear();