feat: Add sketch creation with plane selection, oriented grid and labeled axes

Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
2026-02-09 16:51:15 -07:00
parent b32594a04b
commit ec658360a6
7 changed files with 280 additions and 2 deletions

View File

@@ -1,18 +1,24 @@
#include "ViewportWidget.h"
#include "ViewCube.h"
#include "SketchGrid.h"
#include <QMouseEvent>
#include <QWheelEvent>
#include <QApplication>
#include <QPainter>
#include <QWheelEvent>
#include <QApplication>
ViewportWidget::ViewportWidget(QWidget *parent)
: QOpenGLWidget(parent)
{
m_viewCube = new ViewCube();
m_sketchGrid = new SketchGrid();
}
ViewportWidget::~ViewportWidget()
{
delete m_viewCube;
delete m_sketchGrid;
}
void ViewportWidget::initializeGL()
@@ -21,6 +27,7 @@ void ViewportWidget::initializeGL()
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glEnable(GL_DEPTH_TEST);
m_viewCube->initializeGL();
m_sketchGrid->initializeGL();
}
void ViewportWidget::paintGL()
@@ -42,6 +49,10 @@ void ViewportWidget::paintGL()
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(model.constData());
if (m_currentPlane != SketchPlane::NONE) {
m_sketchGrid->paintGL(static_cast<SketchGrid::SketchPlane>(m_currentPlane), projection, model);
}
// View cube rendering
QMatrix4x4 viewCubeModel;
viewCubeModel.rotate(xRot / 16.0f, 1, 0, 0);
@@ -49,6 +60,12 @@ void ViewportWidget::paintGL()
m_viewCube->paintGL(viewCubeModel, width(), height());
glViewport(0, 0, width(), height());
if (m_currentPlane != SketchPlane::NONE) {
QPainter painter(this);
drawAxisLabels(painter, model, projection);
painter.end();
}
}
void ViewportWidget::resizeGL(int w, int h)
@@ -90,3 +107,77 @@ void ViewportWidget::wheelEvent(QWheelEvent *event)
}
update();
}
void ViewportWidget::startSketch(SketchPlane plane)
{
m_currentPlane = plane;
panX = 0;
panY = 0;
zoom = -20.0f; // Zoom out to see the grid
switch (plane) {
case SketchPlane::XY: // Top view
xRot = -90 * 16;
yRot = 0;
break;
case SketchPlane::XZ: // Front view
xRot = 0;
yRot = 0;
break;
case SketchPlane::YZ: // Right view
xRot = 0;
yRot = 90 * 16;
break;
case SketchPlane::NONE:
break;
}
update();
}
QVector3D ViewportWidget::project(const QVector3D& worldCoord, const QMatrix4x4& modelView, const QMatrix4x4& projection, const QRect& viewport)
{
QVector4D clipCoord = projection * modelView * QVector4D(worldCoord, 1.0);
if (qFuzzyCompare(clipCoord.w(), 0.0f)) {
return QVector3D(-1, -1, -1);
}
QVector3D ndc(clipCoord.x() / clipCoord.w(), clipCoord.y() / clipCoord.w(), clipCoord.z() / clipCoord.w());
float winX = viewport.x() + viewport.width() * (ndc.x() + 1.0) / 2.0;
float winY = viewport.y() + viewport.height() * (1.0 - (ndc.y() + 1.0) / 2.0); // Y is inverted
return QVector3D(winX, winY, (ndc.z() + 1.0) / 2.0);
}
void ViewportWidget::drawAxisLabels(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection)
{
painter.setPen(Qt::white);
painter.setFont(QFont("Arial", 10));
const int range = 50;
const int step = 5;
auto drawLabelsForAxis = [&](int axis_idx) {
for (int i = -range; i <= range; i += step) {
if (i == 0) continue;
QVector3D worldCoord;
worldCoord[axis_idx] = i;
QVector3D screenPos = project(worldCoord, modelView, projection, rect());
if (screenPos.z() < 1.0f) { // Not clipped
painter.drawText(screenPos.toPoint(), QString::number(i));
}
}
};
if (m_currentPlane == SketchPlane::XY) {
drawLabelsForAxis(0); // X
drawLabelsForAxis(1); // Y
} else if (m_currentPlane == SketchPlane::XZ) {
drawLabelsForAxis(0); // X
drawLabelsForAxis(2); // Z
} else if (m_currentPlane == SketchPlane::YZ) {
drawLabelsForAxis(1); // Y
drawLabelsForAxis(2); // Z
}
}