# HG changeset patch # User Teemu Piippo # Date 1652654449 -10800 # Node ID 30204975694a53d400f32bee1358e2f9e3adec67 # Parent 922662adb72add6fb967589bac828c887aa89281 work on circle tool diff -r 922662adb72a -r 30204975694a src/document.cpp --- a/src/document.cpp Thu Apr 14 11:08:20 2022 +0300 +++ b/src/document.cpp Mon May 16 01:40:49 2022 +0300 @@ -27,6 +27,7 @@ #include "tools/pathtool.h" #include "tools/selecttool.h" #include "tools/transformtool.h" +#include "tools/circletool.h" Document::Document( Model* model, @@ -43,6 +44,8 @@ toolsBar{new QToolBar{this}} { this->ui.setupUi(this); + const int listWidth = static_cast(this->width() / 3); + this->ui.viewportListSplitter->setSizes({listWidth * 2, listWidth}); this->ui.toolsBarContainer->setLayout(new QVBoxLayout{this->ui.toolsBarContainer}); this->ui.toolsBarContainer->layout()->addWidget(this->toolsBar); this->ui.listView->setModel(model); @@ -50,7 +53,7 @@ this->ui.viewportFrame->layout()->addWidget(this->renderer); this->toolsBar->setOrientation(Qt::Vertical); this->setMouseTracking(true); - connect(this->ui.splitter, &QSplitter::splitterMoved, this, &Document::splitterChanged); + connect(this->ui.viewportListSplitter, &QSplitter::splitterMoved, this, &Document::splitterChanged); connect(this->renderer, &Canvas::newStatusText, this, &Document::newStatusText); connect(this->renderer, &Canvas::selectionChanged, [&](const QSet& newSelection) { @@ -115,12 +118,12 @@ QByteArray Document::saveSplitterState() const { - return this->ui.splitter->saveState(); + return this->ui.viewportListSplitter->saveState(); } void Document::restoreSplitterState(const QByteArray& state) { - this->ui.splitter->restoreState(state); + this->ui.viewportListSplitter->restoreState(state); } void Document::setRenderPreferences(const gl::RenderPreferences& newPreferences) @@ -161,6 +164,7 @@ this->tools.reserve(3); this->tools.push_back(new SelectTool{this}); this->tools.push_back(new DrawTool{this}); + this->tools.push_back(new CircleTool{this}); this->tools.push_back(new PathTool{this}); this->tools.push_back(new TransformTool{this}); for (BaseTool* const toolInstance : this->tools) diff -r 922662adb72a -r 30204975694a src/document.ui --- a/src/document.ui Thu Apr 14 11:08:20 2022 +0300 +++ b/src/document.ui Mon May 16 01:40:49 2022 +0300 @@ -22,7 +22,7 @@ Qt::Vertical - + Qt::Horizontal @@ -46,13 +46,32 @@ - - - QFrame::StyledPanel + + + true - - QFrame::Raised - + + + + 0 + 0 + 921 + 73 + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + diff -r 922662adb72a -r 30204975694a src/geometry.cpp --- a/src/geometry.cpp Thu Apr 14 11:08:20 2022 +0300 +++ b/src/geometry.cpp Mon May 16 01:40:49 2022 +0300 @@ -235,3 +235,43 @@ } return (sum < 0) ? Winding::Anticlockwise : Winding::Clockwise; } + +/** + * @brief computes the point on a Bezier curve + * @param curve + * @param t scalar between 0 and 1, with t=0 being P0 and t=1 being P3 + * @return point on curve + */ +glm::vec3 geom::pointOnCurve(const BezierCurve &curve, float t) +{ + // clamp t as rounding errors might make it slightly out of bounds + t = std::clamp(t, 0.0f, 1.0f); + const float t_2 = t * t; + const float t_3 = t * t * t; + const float coeffs[3] = { + -1*t_3 +3*t_2 -3*t +1, + +3*t_3 -6*t_2 +3*t, + -3*t_3 +3*t_2, + }; + return coeffs[0] * curve[0] + coeffs[1] * curve[1] + coeffs[2] * curve[2] + t_3 * curve[3]; +} + +/** + * @brief computes the derivative of a point on a Bezier curve + * @param curve + * @param t scalar between 0 and 1, with t=0 being P0 and t=1 being P3 + * @return point on curve + */ +glm::vec3 geom::derivativeOnCurve(const BezierCurve &curve, float t) +{ + // clamp t as rounding errors might make it slightly out of bounds + t = std::clamp(t, 0.0f, 1.0f); + const float t_2 = t * t; + const float coeffs[4] = { + -3*t_2 + 6*t -3, + +9*t_2 -12*t +3, + -9*t_2 + 6*t, + +3*t_2 + }; + return coeffs[0] * curve[0] + coeffs[1] * curve[1] + coeffs[2] * curve[2] + coeffs[3] * curve[3]; +} diff -r 922662adb72a -r 30204975694a src/geometry.h --- a/src/geometry.h Thu Apr 14 11:08:20 2022 +0300 +++ b/src/geometry.h Mon May 16 01:40:49 2022 +0300 @@ -135,4 +135,22 @@ circle.radius * 2 }; } + + struct BezierCurve + { + glm::vec3 points[4]; + const glm::vec3& operator[](int x) const + { + Q_ASSERT(x >= 0 and x < 4); + return this->points[x]; + } + glm::vec3& operator[](int x) + { + Q_ASSERT(x >= 0 and x < 4); + return this->points[x]; + } + }; + + glm::vec3 pointOnCurve(const BezierCurve& curve, float t); + glm::vec3 derivativeOnCurve(const BezierCurve& curve, float t); } diff -r 922662adb72a -r 30204975694a src/tools/circletool.cpp --- a/src/tools/circletool.cpp Thu Apr 14 11:08:20 2022 +0300 +++ b/src/tools/circletool.cpp Mon May 16 01:40:49 2022 +0300 @@ -15,11 +15,35 @@ return tr("Draw circular primitives like circles or discs"); } +std::vector circle(int divisions) +{ + std::vector points; + points.reserve(divisions + 1); + for (int i = 0; i <= divisions; ++i) { + float ang = i * 2.0f * glm::pi() / divisions; + points.push_back({std::sin(ang), std::cos(ang), 0.0f}); + } + return points; +} + void CircleTool::overpaint(Canvas *canvas, QPainter *painter) const { if (this->previewPolygon.size() >= 2) { - canvas->drawWorldPolyline() + for (int i : {0, 1}) { + canvas->drawWorldPoint(painter, this->previewPolygon[i]); + } + painter->setPen(QPen{Qt::green, 2, Qt::DashLine, Qt::RoundCap, Qt::MiterJoin}); + canvas->drawWorldPolyline(painter, {this->previewPolygon[0], this->previewPolygon[1]}); + const float size = glm::distance(this->previewPolygon[1], this->previewPolygon[0]); + glm::mat4 matrix = size * canvas->getGridMatrix(); + matrix[3] = {this->previewPolygon[0], 1}; + std::vector points = circle(16); + for (std::size_t i = 0; i < points.size(); ++i) { + points[i] = matrix * glm::vec4{points[i], 1.0f}; + } + painter->setPen(QPen{Qt::black, 2, Qt::DashLine, Qt::RoundCap, Qt::MiterJoin}); + canvas->drawWorldPolyline(painter, points); } } diff -r 922662adb72a -r 30204975694a src/ui/canvas.cpp --- a/src/ui/canvas.cpp Thu Apr 14 11:08:20 2022 +0300 +++ b/src/ui/canvas.cpp Mon May 16 01:40:49 2022 +0300 @@ -290,6 +290,11 @@ return this->selection; } +const glm::mat4 &Canvas::getGridMatrix() const +{ + return this->gridMatrix; +} + /** * @brief Paints a circle at where @c worldPoint is located on the screen. * @param painter Painter to use to render diff -r 922662adb72a -r 30204975694a src/ui/canvas.h --- a/src/ui/canvas.h Thu Apr 14 11:08:20 2022 +0300 +++ b/src/ui/canvas.h Mon May 16 01:40:49 2022 +0300 @@ -27,6 +27,7 @@ const std::optional& getWorldPosition() const; void adjustGridToView(); const QSet selectedObjects() const; + const glm::mat4& getGridMatrix() const; public Q_SLOTS: void handleSelectionChange(const QSet& selectedIds, const QSet& deselectedIds); void rebuildVertices(Document *document);