feat: Add interactive sketch line drawing to viewport

Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
2026-02-14 19:19:13 -07:00
parent a1cfbc2e3f
commit 8e1ab54cb5
4 changed files with 144 additions and 4 deletions

View File

@@ -3,6 +3,10 @@
#include "SketchGrid.h"
#include "Document.h"
#include "FeatureBrowser.h"
#include "SketchFeature.h"
#include "SketchLine.h"
#include "SketchObject.h"
#include "ApplicationController.h"
#include <QMouseEvent>
#include <QWheelEvent>
#include <QApplication>
@@ -18,6 +22,7 @@ ViewportWidget::ViewportWidget(QWidget *parent)
m_viewCube = new ViewCube();
m_sketchGrid = new SketchGrid();
m_featureBrowser = new FeatureBrowser();
setMouseTracking(true);
}
ViewportWidget::~ViewportWidget()
@@ -29,6 +34,7 @@ ViewportWidget::~ViewportWidget()
void ViewportWidget::setDocument(Document* document)
{
m_document = document;
m_featureBrowser->setDocument(document);
}
@@ -112,6 +118,23 @@ void ViewportWidget::paintGL()
m_sketchGrid->paintGL(static_cast<SketchGrid::SketchPlane>(m_currentPlane), projection, model);
}
if (m_document) {
for (Feature* feature : m_document->features()) {
if (auto sketch = dynamic_cast<SketchFeature*>(feature)) {
drawSketch(sketch);
}
}
}
if (m_isDefiningLine && m_activeTool == static_cast<int>(ApplicationController::ToolType::Line)) {
QVector3D worldPos = unproject(m_currentMousePos);
glBegin(GL_LINES);
glColor3f(1.0, 1.0, 0.0);
glVertex3d(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
glVertex3d(worldPos.x(), worldPos.y(), worldPos.z());
glEnd();
}
// View cube rendering
QMatrix4x4 viewCubeModel;
viewCubeModel.rotate(m_xRot / 16.0f, 1, 0, 0);
@@ -136,11 +159,26 @@ void ViewportWidget::resizeGL(int w, int h)
void ViewportWidget::mousePressEvent(QMouseEvent *event)
{
lastPos = event->pos();
if (event->button() == Qt::LeftButton && m_currentPlane != SketchPlane::NONE && m_activeTool == static_cast<int>(ApplicationController::ToolType::Line)) {
QVector3D worldPos = unproject(event->pos());
gp_Pnt p(worldPos.x(), worldPos.y(), worldPos.z());
if (!m_isDefiningLine) {
m_firstLinePoint = p;
m_isDefiningLine = true;
} else {
emit lineAdded(m_firstLinePoint, p);
m_isDefiningLine = false;
}
update();
} else {
lastPos = event->pos();
}
}
void ViewportWidget::mouseMoveEvent(QMouseEvent *event)
{
m_currentMousePos = event->pos();
int dx = event->pos().x() - lastPos.x();
int dy = event->pos().y() - lastPos.y();
@@ -150,9 +188,11 @@ void ViewportWidget::mouseMoveEvent(QMouseEvent *event)
m_panX += dx / 100.0f;
m_panY -= dy / 100.0f;
} else {
// Rotate
m_xRot += 8 * dy;
m_yRot += 8 * dx;
if (m_currentPlane == SketchPlane::NONE) {
// Rotate
m_xRot += 8 * dy;
m_yRot += 8 * dx;
}
}
}
lastPos = event->pos();
@@ -332,3 +372,79 @@ void ViewportWidget::drawAxisLabels(QPainter& painter, const QMatrix4x4& modelVi
}
}
void ViewportWidget::onActiveToolChanged(int tool)
{
m_activeTool = tool;
m_isDefiningLine = false;
}
QVector3D ViewportWidget::unproject(const QPoint& screenPos)
{
QMatrix4x4 model;
model.translate(m_panX, m_panY, m_zoom);
model.rotate(m_xRot / 16.0f, 1, 0, 0);
model.rotate(m_yRot / 16.0f, 0, 1, 0);
bool invertible;
QMatrix4x4 inv = (projection * model).inverted(&invertible);
if (!invertible) {
return QVector3D();
}
float ndcX = (2.0f * screenPos.x()) / width() - 1.0f;
float ndcY = 1.0f - (2.0f * screenPos.y()) / height();
QVector4D nearPoint_ndc(ndcX, ndcY, -1.0f, 1.0f);
QVector4D farPoint_ndc(ndcX, ndcY, 1.0f, 1.0f);
QVector4D nearPoint_world = inv * nearPoint_ndc;
QVector4D farPoint_world = inv * farPoint_ndc;
if (qFuzzyCompare(nearPoint_world.w(), 0.0f) || qFuzzyCompare(farPoint_world.w(), 0.0f)) {
return QVector3D();
}
nearPoint_world /= nearPoint_world.w();
farPoint_world /= farPoint_world.w();
QVector3D rayOrigin(nearPoint_world);
QVector3D rayDir = (QVector3D(farPoint_world) - rayOrigin).normalized();
QVector3D planeNormal;
switch (m_currentPlane) {
case SketchPlane::XY: planeNormal = QVector3D(0, 0, 1); break;
case SketchPlane::XZ: planeNormal = QVector3D(0, 1, 0); break;
case SketchPlane::YZ: planeNormal = QVector3D(1, 0, 0); break;
case SketchPlane::NONE: return QVector3D();
}
float denom = QVector3D::dotProduct(planeNormal, rayDir);
if (qAbs(denom) > 1e-6) {
QVector3D p0(0,0,0);
float t = QVector3D::dotProduct(p0 - rayOrigin, planeNormal) / denom;
return rayOrigin + t * rayDir;
}
return QVector3D();
}
void ViewportWidget::drawSketch(const SketchFeature* sketch)
{
glDisable(GL_DEPTH_TEST);
glLineWidth(2.0f);
glColor3f(1.0, 1.0, 1.0);
for (const auto& obj : sketch->objects()) {
if (obj->type() == SketchObject::ObjectType::Line) {
auto line = static_cast<const SketchLine*>(obj);
const auto& start = line->startPoint();
const auto& end = line->endPoint();
glBegin(GL_LINES);
glVertex3d(start.X(), start.Y(), start.Z());
glVertex3d(end.X(), end.Y(), end.Z());
glEnd();
}
}
glEnable(GL_DEPTH_TEST);
}