From 23947277242c667881adc3aab23d0809759425ab Mon Sep 17 00:00:00 2001 From: Tanner Collin Date: Tue, 17 Feb 2026 10:53:02 -0700 Subject: [PATCH] refactor: Move rectangle tool logic to RectangleTool class Co-authored-by: aider (gemini/gemini-2.5-pro) --- src/RectangleTool.cpp | 400 ++++++++++++++++++++++++++++++++++++++- src/ViewportWidget.cpp | 420 ++--------------------------------------- 2 files changed, 410 insertions(+), 410 deletions(-) diff --git a/src/RectangleTool.cpp b/src/RectangleTool.cpp index e1a53e2..adf2ae2 100644 --- a/src/RectangleTool.cpp +++ b/src/RectangleTool.cpp @@ -1,8 +1,13 @@ #include "RectangleTool.h" #include "ViewportWidget.h" +#include "Camera.h" #include #include #include +#include +#include +#include +#include RectangleTool::RectangleTool(ViewportWidget* viewport) : SketchTool(viewport) @@ -26,7 +31,86 @@ void RectangleTool::deactivate() void RectangleTool::mousePressEvent(QMouseEvent *event) { - // To be implemented + gp_Pnt p; + if (!m_isDefiningRectangle) { + if (m_viewport->isSnappingOrigin()) { + p.SetCoord(0, 0, 0); + } else if (m_viewport->isSnappingVertex()) { + p = m_viewport->snapVertex(); + } else { + QVector3D worldPos = m_viewport->unproject(event->pos(), m_viewport->currentPlane()); + p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z()); + } + m_firstRectanglePoint = p; + m_isDefiningRectangle = true; + m_viewport->setProperty("widthInput", ""); + m_viewport->setProperty("heightInput", ""); + m_viewport->setProperty("dimensionEditMode", "height"); + } else { + QVector3D worldPos; + QVector3D startPos(m_firstRectanglePoint.X(), m_firstRectanglePoint.Y(), m_firstRectanglePoint.Z()); + + QString widthInput = m_viewport->property("widthInput").toString(); + QString heightInput = m_viewport->property("heightInput").toString(); + bool widthFromInput = false, heightFromInput = false; + double inputWidth = 0, inputHeight = 0; + + if (!widthInput.isEmpty()) { + bool ok; + inputWidth = widthInput.toDouble(&ok); + if (ok) widthFromInput = true; + } + if (!heightInput.isEmpty()) { + bool ok; + inputHeight = heightInput.toDouble(&ok); + if (ok) heightFromInput = true; + } + + if (widthFromInput || heightFromInput) { + QVector3D mousePos = m_viewport->unproject(event->pos(), m_viewport->currentPlane()); + QVector3D mouseDir = mousePos - startPos; + double current_w, current_h; + if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { + current_w = qAbs(mouseDir.x()); + current_h = qAbs(mouseDir.z()); + } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { + current_w = qAbs(mouseDir.x()); + current_h = qAbs(mouseDir.y()); + } else { // YZ + current_w = qAbs(mouseDir.y()); + current_h = qAbs(mouseDir.z()); + } + double rect_w = widthFromInput ? inputWidth : current_w; + double rect_h = heightFromInput ? inputHeight : current_h; + int signX = (mouseDir.x() >= 0) ? 1 : -1; + int signY = (mouseDir.y() >= 0) ? 1 : -1; + int signZ = (mouseDir.z() >= 0) ? 1 : -1; + worldPos = startPos; + if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { + worldPos.setX(startPos.x() + signX * rect_w); + worldPos.setZ(startPos.z() + signZ * rect_h); + } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { + worldPos.setX(startPos.x() + signX * rect_w); + worldPos.setY(startPos.y() + signY * rect_h); + } else { // YZ + worldPos.setY(startPos.y() + signY * rect_w); + worldPos.setZ(startPos.z() + signZ * rect_h); + } + } else { + if (m_viewport->isSnappingOrigin()) { + worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0); + } else if (m_viewport->isSnappingVertex()) { + worldPos = QVector3D(m_viewport->snapVertex().X(), m_viewport->snapVertex().Y(), m_viewport->snapVertex().Z()); + } else { + worldPos = m_viewport->unproject(event->pos(), m_viewport->currentPlane()); + } + } + p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z()); + emit m_viewport->rectangleAdded(m_firstRectanglePoint, p); + m_isDefiningRectangle = false; + m_viewport->setProperty("widthInput", ""); + m_viewport->setProperty("heightInput", ""); + } } void RectangleTool::mouseMoveEvent(QMouseEvent *event) @@ -36,15 +120,323 @@ void RectangleTool::mouseMoveEvent(QMouseEvent *event) void RectangleTool::keyPressEvent(QKeyEvent *event) { - // To be implemented + if (m_isDefiningRectangle) { + if (event->key() == Qt::Key_Tab) { + QString currentMode = m_viewport->property("dimensionEditMode").toString(); + if (currentMode == "width") { + m_viewport->setProperty("dimensionEditMode", "height"); + } else { + m_viewport->setProperty("dimensionEditMode", "width"); + } + m_viewport->update(); + return; + } + + QString editMode = m_viewport->property("dimensionEditMode").toString(); + const char* propertyName = (editMode == "width") ? "widthInput" : "heightInput"; + QString currentInput = m_viewport->property(propertyName).toString(); + + if (event->key() >= Qt::Key_0 && event->key() <= Qt::Key_9) { + currentInput += event->text(); + m_viewport->setProperty(propertyName, currentInput); + m_viewport->update(); + return; + } else if (event->key() == Qt::Key_Period) { + if (!currentInput.contains('.')) { + currentInput += '.'; + m_viewport->setProperty(propertyName, currentInput); + m_viewport->update(); + } + return; + } else if (event->key() == Qt::Key_Backspace) { + if (!currentInput.isEmpty()) { + currentInput.chop(1); + m_viewport->setProperty(propertyName, currentInput); + m_viewport->update(); + } + return; + } else if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) { + QVector3D worldPos; + QVector3D startPos(m_firstRectanglePoint.X(), m_firstRectanglePoint.Y(), m_firstRectanglePoint.Z()); + + QString widthInput = m_viewport->property("widthInput").toString(); + QString heightInput = m_viewport->property("heightInput").toString(); + bool widthFromInput = false, heightFromInput = false; + double inputWidth = 0, inputHeight = 0; + + if (!widthInput.isEmpty()) { + bool ok; + inputWidth = widthInput.toDouble(&ok); + if (ok) widthFromInput = true; + } + if (!heightInput.isEmpty()) { + bool ok; + inputHeight = heightInput.toDouble(&ok); + if (ok) heightFromInput = true; + } + + if (widthFromInput || heightFromInput) { + QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); + QVector3D mouseDir = mousePos - startPos; + double current_w, current_h; + if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { + current_w = qAbs(mouseDir.x()); + current_h = qAbs(mouseDir.z()); + } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { + current_w = qAbs(mouseDir.x()); + current_h = qAbs(mouseDir.y()); + } else { // YZ + current_w = qAbs(mouseDir.y()); + current_h = qAbs(mouseDir.z()); + } + double rect_w = widthFromInput ? inputWidth : current_w; + double rect_h = heightFromInput ? inputHeight : current_h; + int signX = (mouseDir.x() >= 0) ? 1 : -1; + int signY = (mouseDir.y() >= 0) ? 1 : -1; + int signZ = (mouseDir.z() >= 0) ? 1 : -1; + worldPos = startPos; + if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { + worldPos.setX(startPos.x() + signX * rect_w); + worldPos.setZ(startPos.z() + signZ * rect_h); + } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { + worldPos.setX(startPos.x() + signX * rect_w); + worldPos.setY(startPos.y() + signY * rect_h); + } else { // YZ + worldPos.setY(startPos.y() + signY * rect_w); + worldPos.setZ(startPos.z() + signZ * rect_h); + } + } else { + worldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); + } + + gp_Pnt p; + p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z()); + + emit m_viewport->rectangleAdded(m_firstRectanglePoint, p); + deactivate(); + m_viewport->update(); + return; + } else if (event->key() == Qt::Key_Escape) { + deactivate(); + m_viewport->deactivateActiveTool(); + m_viewport->update(); + return; + } + } } void RectangleTool::paintGL() { - // To be implemented + if (m_isDefiningRectangle) { + QVector vertices; + QVector3D worldPos; + QVector3D startPos(m_firstRectanglePoint.X(), m_firstRectanglePoint.Y(), m_firstRectanglePoint.Z()); + + QString widthInput = m_viewport->property("widthInput").toString(); + QString heightInput = m_viewport->property("heightInput").toString(); + bool widthFromInput = false; + bool heightFromInput = false; + double inputWidth = 0, inputHeight = 0; + + if (!widthInput.isEmpty()) { + bool ok; + inputWidth = widthInput.toDouble(&ok); + if (ok) widthFromInput = true; + } + if (!heightInput.isEmpty()) { + bool ok; + inputHeight = heightInput.toDouble(&ok); + if (ok) heightFromInput = true; + } + + QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); + + if (widthFromInput || heightFromInput) { + QVector3D mouseDir = mousePos - startPos; + double current_w, current_h; + if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { + current_w = qAbs(mouseDir.x()); + current_h = qAbs(mouseDir.z()); + } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { + current_w = qAbs(mouseDir.x()); + current_h = qAbs(mouseDir.y()); + } else { // YZ + current_w = qAbs(mouseDir.y()); + current_h = qAbs(mouseDir.z()); + } + double rect_w = widthFromInput ? inputWidth : current_w; + double rect_h = heightFromInput ? inputHeight : current_h; + int signX = (mouseDir.x() >= 0) ? 1 : -1; + int signY = (mouseDir.y() >= 0) ? 1 : -1; + int signZ = (mouseDir.z() >= 0) ? 1 : -1; + worldPos = startPos; + if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { + worldPos.setX(startPos.x() + signX * rect_w); + worldPos.setZ(startPos.z() + signZ * rect_h); + } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { + worldPos.setX(startPos.x() + signX * rect_w); + worldPos.setY(startPos.y() + signY * rect_h); + } else { // YZ + worldPos.setY(startPos.y() + signY * rect_w); + worldPos.setZ(startPos.z() + signZ * rect_h); + } + } else { + worldPos = mousePos; + if (m_viewport->isSnappingOrigin()) { + worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0); + } else if (m_viewport->isSnappingVertex()) { + worldPos.setX(m_viewport->snapVertex().X()); worldPos.setY(m_viewport->snapVertex().Y()); worldPos.setZ(m_viewport->snapVertex().Z()); + } + } + + QVector3D p1 = startPos; + QVector3D p2, p3, p4; + p3 = worldPos; + + if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { + p2.setX(p3.x()); p2.setY(p1.y()); p2.setZ(p1.z()); + p4.setX(p1.x()); p4.setY(p1.y()); p4.setZ(p3.z()); + } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { + p2.setX(p3.x()); p2.setY(p1.y()); p2.setZ(p1.z()); + p4.setX(p1.x()); p4.setY(p3.y()); p4.setZ(p1.z()); + } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) { + p2.setX(p1.x()); p2.setY(p3.y()); p2.setZ(p1.z()); + p4.setX(p1.x()); p4.setY(p1.y()); p4.setZ(p3.z()); + } + + vertices << p1.x() << p1.y() << p1.z(); + vertices << p2.x() << p2.y() << p2.z(); + vertices << p2.x() << p2.y() << p2.z(); + vertices << p3.x() << p3.y() << p3.z(); + vertices << p3.x() << p3.y() << p3.z(); + vertices << p4.x() << p4.y() << p4.z(); + vertices << p4.x() << p4.y() << p4.z(); + vertices << p1.x() << p1.y() << p1.z(); + + m_viewport->shaderProgram()->setUniformValue(m_viewport->colorLoc(), QVector4D(1.0f, 1.0f, 0.0f, 1.0f)); + m_viewport->vbo().bind(); + m_viewport->vbo().allocate(vertices.constData(), vertices.size() * sizeof(GLfloat)); + glDrawArrays(GL_LINES, 0, 8); + } } void RectangleTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection) { - // To be implemented + if (m_isDefiningRectangle) { + QVector3D worldPos; + QVector3D p1_3d(m_firstRectanglePoint.X(), m_firstRectanglePoint.Y(), m_firstRectanglePoint.Z()); + + QString widthInput = m_viewport->property("widthInput").toString(); + QString heightInput = m_viewport->property("heightInput").toString(); + bool widthFromInput = false; + bool heightFromInput = false; + double inputWidth = 0, inputHeight = 0; + + if (!widthInput.isEmpty()) { + bool ok; + inputWidth = widthInput.toDouble(&ok); + if (ok) widthFromInput = true; + } + if (!heightInput.isEmpty()) { + bool ok; + inputHeight = heightInput.toDouble(&ok); + if (ok) heightFromInput = true; + } + + QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); + + if (widthFromInput || heightFromInput) { + QVector3D mouseDir = mousePos - p1_3d; + double current_w, current_h; + if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { + current_w = qAbs(mouseDir.x()); + current_h = qAbs(mouseDir.z()); + } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { + current_w = qAbs(mouseDir.x()); + current_h = qAbs(mouseDir.y()); + } else { // YZ + current_w = qAbs(mouseDir.y()); + current_h = qAbs(mouseDir.z()); + } + double rect_w = widthFromInput ? inputWidth : current_w; + double rect_h = heightFromInput ? inputHeight : current_h; + int signX = (mouseDir.x() >= 0) ? 1 : -1; + int signY = (mouseDir.y() >= 0) ? 1 : -1; + int signZ = (mouseDir.z() >= 0) ? 1 : -1; + worldPos = p1_3d; + if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { + worldPos.setX(p1_3d.x() + signX * rect_w); + worldPos.setZ(p1_3d.z() + signZ * rect_h); + } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { + worldPos.setX(p1_3d.x() + signX * rect_w); + worldPos.setY(p1_3d.y() + signY * rect_h); + } else { // YZ + worldPos.setY(p1_3d.y() + signY * rect_w); + worldPos.setZ(p1_3d.z() + signZ * rect_h); + } + } else { + worldPos = mousePos; + if (m_viewport->isSnappingOrigin()) { + worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0); + } else if (m_viewport->isSnappingVertex()) { + worldPos.setX(m_viewport->snapVertex().X()); worldPos.setY(m_viewport->snapVertex().Y()); worldPos.setZ(m_viewport->snapVertex().Z()); + } + } + QVector3D p3_3d = worldPos; + QVector3D p2_3d, p4_3d; + + double w, h; + + if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { + p2_3d.setX(p3_3d.x()); p2_3d.setY(p1_3d.y()); p2_3d.setZ(p1_3d.z()); + p4_3d.setX(p1_3d.x()); p4_3d.setY(p1_3d.y()); p4_3d.setZ(p3_3d.z()); + w = qAbs(p3_3d.x() - p1_3d.x()); + h = qAbs(p3_3d.z() - p1_3d.z()); + } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { + p2_3d.setX(p3_3d.x()); p2_3d.setY(p1_3d.y()); p2_3d.setZ(p1_3d.z()); + p4_3d.setX(p1_3d.x()); p4_3d.setY(p3_3d.y()); p4_3d.setZ(p1_3d.z()); + w = qAbs(p3_3d.x() - p1_3d.x()); + h = qAbs(p3_3d.y() - p1_3d.y()); + } else { // YZ + p2_3d.setX(p1_3d.x()); p2_3d.setY(p3_3d.y()); p2_3d.setZ(p1_3d.z()); + p4_3d.setX(p1_3d.x()); p4_3d.setY(p1_3d.y()); p4_3d.setZ(p3_3d.z()); + w = qAbs(p3_3d.y() - p1_3d.y()); + h = qAbs(p3_3d.z() - p1_3d.z()); + } + + painter.setRenderHint(QPainter::Antialiasing); + QFontMetrics fm(painter.font()); + + // Width dimension + QVector3D widthTextPos3D = (p1_3d + p2_3d) / 2.0f; + QVector3D screenPosW = m_viewport->project(widthTextPos3D, modelView, projection, m_viewport->rect()); + if (screenPosW.z() < 1.0f) { + QString widthText = widthFromInput ? widthInput : QString::number(w, 'f', 2); + QRect textRect = fm.boundingRect(widthText + "__"); + textRect.moveCenter(screenPosW.toPoint() + QPoint(0, (p3_3d.z() > p1_3d.z() || p3_3d.y() > p1_3d.y()) ? -15 : 15)); + if (m_viewport->property("dimensionEditMode").toString() == "width") { + painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(64, 128, 255)); + } else { + painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(50, 50, 50)); + } + painter.setPen(Qt::white); + painter.drawText(textRect, Qt::AlignCenter, widthText); + } + + // Height dimension + QVector3D heightTextPos3D = (p2_3d + p3_3d) / 2.0f; + QVector3D screenPosH = m_viewport->project(heightTextPos3D, modelView, projection, m_viewport->rect()); + if (screenPosH.z() < 1.0f) { + QString heightText = heightFromInput ? heightInput : QString::number(h, 'f', 2); + QRect textRect = fm.boundingRect(heightText + "__"); + textRect.moveCenter(screenPosH.toPoint() + QPoint((p3_3d.x() > p1_3d.x()) ? 15 : -15, 0)); + if (m_viewport->property("dimensionEditMode").toString() == "height") { + painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(64, 128, 255)); + } else { + painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(50, 50, 50)); + } + painter.setPen(Qt::white); + painter.drawText(textRect, Qt::AlignCenter, heightText); + } + } } diff --git a/src/ViewportWidget.cpp b/src/ViewportWidget.cpp index e619649..d1e1095 100644 --- a/src/ViewportWidget.cpp +++ b/src/ViewportWidget.cpp @@ -9,6 +9,7 @@ #include "SketchRectangle.h" #include "SketchObject.h" #include "ApplicationController.h" +#include "RectangleTool.h" #include #include #include @@ -56,6 +57,8 @@ ViewportWidget::ViewportWidget(QWidget *parent) m_toolIcons.insert(static_cast(ApplicationController::ToolType::Circle), new QSvgRenderer(QString(":/icons/circle.svg"), this)); m_cursorRenderer = new QSvgRenderer(QString(":/icons/cursor.svg"), this); + + m_sketchTools.insert(static_cast(ApplicationController::ToolType::Rectangle), new RectangleTool(this)); } ViewportWidget::~ViewportWidget() @@ -197,98 +200,6 @@ void ViewportWidget::paintGL() glDisable(GL_BLEND); } - if (m_isDefiningRectangle && m_activeTool == static_cast(ApplicationController::ToolType::Rectangle)) { - vertices.clear(); - QVector3D worldPos; - QVector3D startPos(m_firstRectanglePoint.X(), m_firstRectanglePoint.Y(), m_firstRectanglePoint.Z()); - - QString widthInput = property("widthInput").toString(); - QString heightInput = property("heightInput").toString(); - bool widthFromInput = false; - bool heightFromInput = false; - double inputWidth = 0, inputHeight = 0; - - if (!widthInput.isEmpty()) { - bool ok; - inputWidth = widthInput.toDouble(&ok); - if (ok) widthFromInput = true; - } - if (!heightInput.isEmpty()) { - bool ok; - inputHeight = heightInput.toDouble(&ok); - if (ok) heightFromInput = true; - } - - QVector3D mousePos = unproject(m_currentMousePos, m_currentPlane); - - if (widthFromInput || heightFromInput) { - QVector3D mouseDir = mousePos - startPos; - double current_w, current_h; - if (m_currentPlane == SketchPlane::XY) { - current_w = qAbs(mouseDir.x()); - current_h = qAbs(mouseDir.z()); - } else if (m_currentPlane == SketchPlane::XZ) { - current_w = qAbs(mouseDir.x()); - current_h = qAbs(mouseDir.y()); - } else { // YZ - current_w = qAbs(mouseDir.y()); - current_h = qAbs(mouseDir.z()); - } - double rect_w = widthFromInput ? inputWidth : current_w; - double rect_h = heightFromInput ? inputHeight : current_h; - int signX = (mouseDir.x() >= 0) ? 1 : -1; - int signY = (mouseDir.y() >= 0) ? 1 : -1; - int signZ = (mouseDir.z() >= 0) ? 1 : -1; - worldPos = startPos; - if (m_currentPlane == SketchPlane::XY) { - worldPos.setX(startPos.x() + signX * rect_w); - worldPos.setZ(startPos.z() + signZ * rect_h); - } else if (m_currentPlane == SketchPlane::XZ) { - worldPos.setX(startPos.x() + signX * rect_w); - worldPos.setY(startPos.y() + signY * rect_h); - } else { // YZ - worldPos.setY(startPos.y() + signY * rect_w); - worldPos.setZ(startPos.z() + signZ * rect_h); - } - } else { - worldPos = mousePos; - if (m_isSnappingOrigin) { - worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0); - } else if (m_isSnappingVertex) { - worldPos.setX(m_snapVertex.X()); worldPos.setY(m_snapVertex.Y()); worldPos.setZ(m_snapVertex.Z()); - } - } - - QVector3D p1 = startPos; - QVector3D p2, p3, p4; - p3 = worldPos; - - if (m_currentPlane == SketchPlane::XY) { - p2.setX(p3.x()); p2.setY(p1.y()); p2.setZ(p1.z()); - p4.setX(p1.x()); p4.setY(p1.y()); p4.setZ(p3.z()); - } else if (m_currentPlane == SketchPlane::XZ) { - p2.setX(p3.x()); p2.setY(p1.y()); p2.setZ(p1.z()); - p4.setX(p1.x()); p4.setY(p3.y()); p4.setZ(p1.z()); - } else if (m_currentPlane == SketchPlane::YZ) { - p2.setX(p1.x()); p2.setY(p3.y()); p2.setZ(p1.z()); - p4.setX(p1.x()); p4.setY(p1.y()); p4.setZ(p3.z()); - } - - vertices << p1.x() << p1.y() << p1.z(); - vertices << p2.x() << p2.y() << p2.z(); - vertices << p2.x() << p2.y() << p2.z(); - vertices << p3.x() << p3.y() << p3.z(); - vertices << p3.x() << p3.y() << p3.z(); - vertices << p4.x() << p4.y() << p4.z(); - vertices << p4.x() << p4.y() << p4.z(); - vertices << p1.x() << p1.y() << p1.z(); - - m_shaderProgram->setUniformValue(m_colorLoc, QVector4D(1.0f, 1.0f, 0.0f, 1.0f)); - m_vbo.bind(); - m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat)); - glDrawArrays(GL_LINES, 0, 8); - } - if (m_activeSketchTool) { m_activeSketchTool->paintGL(); } @@ -311,123 +222,6 @@ void ViewportWidget::paintGL() } m_featureBrowser->paint(painter, width(), height()); - if (m_isDefiningRectangle && m_activeTool == static_cast(ApplicationController::ToolType::Rectangle)) { - QVector3D worldPos; - QVector3D p1_3d(m_firstRectanglePoint.X(), m_firstRectanglePoint.Y(), m_firstRectanglePoint.Z()); - - QString widthInput = property("widthInput").toString(); - QString heightInput = property("heightInput").toString(); - bool widthFromInput = false; - bool heightFromInput = false; - double inputWidth = 0, inputHeight = 0; - - if (!widthInput.isEmpty()) { - bool ok; - inputWidth = widthInput.toDouble(&ok); - if (ok) widthFromInput = true; - } - if (!heightInput.isEmpty()) { - bool ok; - inputHeight = heightInput.toDouble(&ok); - if (ok) heightFromInput = true; - } - - QVector3D mousePos = unproject(m_currentMousePos, m_currentPlane); - - if (widthFromInput || heightFromInput) { - QVector3D mouseDir = mousePos - p1_3d; - double current_w, current_h; - if (m_currentPlane == SketchPlane::XY) { - current_w = qAbs(mouseDir.x()); - current_h = qAbs(mouseDir.z()); - } else if (m_currentPlane == SketchPlane::XZ) { - current_w = qAbs(mouseDir.x()); - current_h = qAbs(mouseDir.y()); - } else { // YZ - current_w = qAbs(mouseDir.y()); - current_h = qAbs(mouseDir.z()); - } - double rect_w = widthFromInput ? inputWidth : current_w; - double rect_h = heightFromInput ? inputHeight : current_h; - int signX = (mouseDir.x() >= 0) ? 1 : -1; - int signY = (mouseDir.y() >= 0) ? 1 : -1; - int signZ = (mouseDir.z() >= 0) ? 1 : -1; - worldPos = p1_3d; - if (m_currentPlane == SketchPlane::XY) { - worldPos.setX(p1_3d.x() + signX * rect_w); - worldPos.setZ(p1_3d.z() + signZ * rect_h); - } else if (m_currentPlane == SketchPlane::XZ) { - worldPos.setX(p1_3d.x() + signX * rect_w); - worldPos.setY(p1_3d.y() + signY * rect_h); - } else { // YZ - worldPos.setY(p1_3d.y() + signY * rect_w); - worldPos.setZ(p1_3d.z() + signZ * rect_h); - } - } else { - worldPos = mousePos; - if (m_isSnappingOrigin) { - worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0); - } else if (m_isSnappingVertex) { - worldPos.setX(m_snapVertex.X()); worldPos.setY(m_snapVertex.Y()); worldPos.setZ(m_snapVertex.Z()); - } - } - QVector3D p3_3d = worldPos; - QVector3D p2_3d, p4_3d; - - double w, h; - - if (m_currentPlane == SketchPlane::XY) { - p2_3d.setX(p3_3d.x()); p2_3d.setY(p1_3d.y()); p2_3d.setZ(p1_3d.z()); - p4_3d.setX(p1_3d.x()); p4_3d.setY(p1_3d.y()); p4_3d.setZ(p3_3d.z()); - w = qAbs(p3_3d.x() - p1_3d.x()); - h = qAbs(p3_3d.z() - p1_3d.z()); - } else if (m_currentPlane == SketchPlane::XZ) { - p2_3d.setX(p3_3d.x()); p2_3d.setY(p1_3d.y()); p2_3d.setZ(p1_3d.z()); - p4_3d.setX(p1_3d.x()); p4_3d.setY(p3_3d.y()); p4_3d.setZ(p1_3d.z()); - w = qAbs(p3_3d.x() - p1_3d.x()); - h = qAbs(p3_3d.y() - p1_3d.y()); - } else { // YZ - p2_3d.setX(p1_3d.x()); p2_3d.setY(p3_3d.y()); p2_3d.setZ(p1_3d.z()); - p4_3d.setX(p1_3d.x()); p4_3d.setY(p1_3d.y()); p4_3d.setZ(p3_3d.z()); - w = qAbs(p3_3d.y() - p1_3d.y()); - h = qAbs(p3_3d.z() - p1_3d.z()); - } - - painter.setRenderHint(QPainter::Antialiasing); - QFontMetrics fm(painter.font()); - - // Width dimension - QVector3D widthTextPos3D = (p1_3d + p2_3d) / 2.0f; - QVector3D screenPosW = project(widthTextPos3D, model, projection, rect()); - if (screenPosW.z() < 1.0f) { - QString widthText = widthFromInput ? widthInput : QString::number(w, 'f', 2); - QRect textRect = fm.boundingRect(widthText + "__"); - textRect.moveCenter(screenPosW.toPoint() + QPoint(0, (p3_3d.z() > p1_3d.z() || p3_3d.y() > p1_3d.y()) ? -15 : 15)); - if (property("dimensionEditMode").toString() == "width") { - painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(64, 128, 255)); - } else { - painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(50, 50, 50)); - } - painter.setPen(Qt::white); - painter.drawText(textRect, Qt::AlignCenter, widthText); - } - - // Height dimension - QVector3D heightTextPos3D = (p2_3d + p3_3d) / 2.0f; - QVector3D screenPosH = project(heightTextPos3D, model, projection, rect()); - if (screenPosH.z() < 1.0f) { - QString heightText = heightFromInput ? heightInput : QString::number(h, 'f', 2); - QRect textRect = fm.boundingRect(heightText + "__"); - textRect.moveCenter(screenPosH.toPoint() + QPoint((p3_3d.x() > p1_3d.x()) ? 15 : -15, 0)); - if (property("dimensionEditMode").toString() == "height") { - painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(64, 128, 255)); - } else { - painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(50, 50, 50)); - } - painter.setPen(Qt::white); - painter.drawText(textRect, Qt::AlignCenter, heightText); - } - } if (m_activeSketchTool) { m_activeSketchTool->paint2D(painter, model, projection); @@ -461,91 +255,6 @@ void ViewportWidget::mousePressEvent(QMouseEvent *event) return; } - if (m_currentPlane != SketchPlane::NONE && m_activeTool == static_cast(ApplicationController::ToolType::Rectangle)) { - gp_Pnt p; - if (!m_isDefiningRectangle) { - if (m_isSnappingOrigin) { - p.SetCoord(0, 0, 0); - } else if (m_isSnappingVertex) { - p = m_snapVertex; - } else { - QVector3D worldPos = unproject(event->pos(), m_currentPlane); - p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z()); - } - m_firstRectanglePoint = p; - m_isDefiningRectangle = true; - setProperty("widthInput", ""); - setProperty("heightInput", ""); - setProperty("dimensionEditMode", "height"); - } else { - QVector3D worldPos; - QVector3D startPos(m_firstRectanglePoint.X(), m_firstRectanglePoint.Y(), m_firstRectanglePoint.Z()); - - QString widthInput = property("widthInput").toString(); - QString heightInput = property("heightInput").toString(); - bool widthFromInput = false, heightFromInput = false; - double inputWidth = 0, inputHeight = 0; - - if (!widthInput.isEmpty()) { - bool ok; - inputWidth = widthInput.toDouble(&ok); - if (ok) widthFromInput = true; - } - if (!heightInput.isEmpty()) { - bool ok; - inputHeight = heightInput.toDouble(&ok); - if (ok) heightFromInput = true; - } - - if (widthFromInput || heightFromInput) { - QVector3D mousePos = unproject(event->pos(), m_currentPlane); - QVector3D mouseDir = mousePos - startPos; - double current_w, current_h; - if (m_currentPlane == SketchPlane::XY) { - current_w = qAbs(mouseDir.x()); - current_h = qAbs(mouseDir.z()); - } else if (m_currentPlane == SketchPlane::XZ) { - current_w = qAbs(mouseDir.x()); - current_h = qAbs(mouseDir.y()); - } else { // YZ - current_w = qAbs(mouseDir.y()); - current_h = qAbs(mouseDir.z()); - } - double rect_w = widthFromInput ? inputWidth : current_w; - double rect_h = heightFromInput ? inputHeight : current_h; - int signX = (mouseDir.x() >= 0) ? 1 : -1; - int signY = (mouseDir.y() >= 0) ? 1 : -1; - int signZ = (mouseDir.z() >= 0) ? 1 : -1; - worldPos = startPos; - if (m_currentPlane == SketchPlane::XY) { - worldPos.setX(startPos.x() + signX * rect_w); - worldPos.setZ(startPos.z() + signZ * rect_h); - } else if (m_currentPlane == SketchPlane::XZ) { - worldPos.setX(startPos.x() + signX * rect_w); - worldPos.setY(startPos.y() + signY * rect_h); - } else { // YZ - worldPos.setY(startPos.y() + signY * rect_w); - worldPos.setZ(startPos.z() + signZ * rect_h); - } - } else { - if (m_isSnappingOrigin) { - worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0); - } else if (m_isSnappingVertex) { - worldPos = QVector3D(m_snapVertex.X(), m_snapVertex.Y(), m_snapVertex.Z()); - } else { - worldPos = unproject(event->pos(), m_currentPlane); - } - } - p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z()); - emit rectangleAdded(m_firstRectanglePoint, p); - m_isDefiningRectangle = false; - setProperty("widthInput", ""); - setProperty("heightInput", ""); - } - update(); - return; - } - } else { lastPos = event->pos(); } @@ -726,121 +435,11 @@ void ViewportWidget::keyPressEvent(QKeyEvent *event) { if (m_activeSketchTool) { m_activeSketchTool->keyPressEvent(event); - update(); return; } - if (m_isDefiningRectangle && m_activeTool == static_cast(ApplicationController::ToolType::Rectangle)) { - if (event->key() == Qt::Key_Tab) { - QString currentMode = property("dimensionEditMode").toString(); - if (currentMode == "width") { - setProperty("dimensionEditMode", "height"); - } else { - setProperty("dimensionEditMode", "width"); - } - update(); - return; - } - - QString editMode = property("dimensionEditMode").toString(); - const char* propertyName = (editMode == "width") ? "widthInput" : "heightInput"; - QString currentInput = property(propertyName).toString(); - - if (event->key() >= Qt::Key_0 && event->key() <= Qt::Key_9) { - currentInput += event->text(); - setProperty(propertyName, currentInput); - update(); - return; - } else if (event->key() == Qt::Key_Period) { - if (!currentInput.contains('.')) { - currentInput += '.'; - setProperty(propertyName, currentInput); - update(); - return; - } - } else if (event->key() == Qt::Key_Backspace) { - if (!currentInput.isEmpty()) { - currentInput.chop(1); - setProperty(propertyName, currentInput); - update(); - return; - } - } else if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) { - QVector3D worldPos; - QVector3D startPos(m_firstRectanglePoint.X(), m_firstRectanglePoint.Y(), m_firstRectanglePoint.Z()); - - QString widthInput = property("widthInput").toString(); - QString heightInput = property("heightInput").toString(); - bool widthFromInput = false, heightFromInput = false; - double inputWidth = 0, inputHeight = 0; - - if (!widthInput.isEmpty()) { - bool ok; - inputWidth = widthInput.toDouble(&ok); - if (ok) widthFromInput = true; - } - if (!heightInput.isEmpty()) { - bool ok; - inputHeight = heightInput.toDouble(&ok); - if (ok) heightFromInput = true; - } - - if (widthFromInput || heightFromInput) { - QVector3D mousePos = unproject(m_currentMousePos, m_currentPlane); - QVector3D mouseDir = mousePos - startPos; - double current_w, current_h; - if (m_currentPlane == SketchPlane::XY) { - current_w = qAbs(mouseDir.x()); - current_h = qAbs(mouseDir.z()); - } else if (m_currentPlane == SketchPlane::XZ) { - current_w = qAbs(mouseDir.x()); - current_h = qAbs(mouseDir.y()); - } else { // YZ - current_w = qAbs(mouseDir.y()); - current_h = qAbs(mouseDir.z()); - } - double rect_w = widthFromInput ? inputWidth : current_w; - double rect_h = heightFromInput ? inputHeight : current_h; - int signX = (mouseDir.x() >= 0) ? 1 : -1; - int signY = (mouseDir.y() >= 0) ? 1 : -1; - int signZ = (mouseDir.z() >= 0) ? 1 : -1; - worldPos = startPos; - if (m_currentPlane == SketchPlane::XY) { - worldPos.setX(startPos.x() + signX * rect_w); - worldPos.setZ(startPos.z() + signZ * rect_h); - } else if (m_currentPlane == SketchPlane::XZ) { - worldPos.setX(startPos.x() + signX * rect_w); - worldPos.setY(startPos.y() + signY * rect_h); - } else { // YZ - worldPos.setY(startPos.y() + signY * rect_w); - worldPos.setZ(startPos.z() + signZ * rect_h); - } - } else { - worldPos = unproject(m_currentMousePos, m_currentPlane); - } - - gp_Pnt p; - p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z()); - - emit rectangleAdded(m_firstRectanglePoint, p); - m_isDefiningRectangle = false; - setProperty("widthInput", ""); - setProperty("heightInput", ""); - update(); - return; - } - } - if (event->key() == Qt::Key_Escape) { - if (m_isDefiningRectangle) { - m_isDefiningRectangle = false; - setProperty("widthInput", ""); - setProperty("heightInput", ""); - emit toolDeactivated(); - update(); - return; - } - else if (m_isSelectingPlane) { + if (m_isSelectingPlane) { m_isSelectingPlane = false; m_highlightedPlane = SketchPlane::NONE; m_currentPlane = SketchPlane::XY; @@ -1045,9 +644,18 @@ void ViewportWidget::drawAxisLabels(QPainter& painter, const QMatrix4x4& modelVi void ViewportWidget::onActiveToolChanged(int tool) { + if (m_activeSketchTool) { + m_activeSketchTool->deactivate(); + m_activeSketchTool = nullptr; + } + m_activeTool = tool; m_isDefiningLine = false; - m_isDefiningRectangle = false; + + if (m_sketchTools.contains(tool)) { + m_activeSketchTool = m_sketchTools.value(tool); + m_activeSketchTool->activate(); + } if (tool == static_cast(ApplicationController::ToolType::None)) { unsetCursor();