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:
@@ -1,6 +1,7 @@
|
||||
#include "ApplicationController.h"
|
||||
#include "Document.h"
|
||||
#include "SketchFeature.h"
|
||||
#include "SketchLine.h"
|
||||
#include "MainWindow.h"
|
||||
|
||||
#include <QInputDialog>
|
||||
@@ -126,6 +127,13 @@ void ApplicationController::beginSketchCreation()
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationController::addLine(const gp_Pnt& start, const gp_Pnt& end)
|
||||
{
|
||||
if (m_activeSketch) {
|
||||
m_activeSketch->addObject(new SketchLine(start, end));
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationController::endSketch()
|
||||
{
|
||||
m_activeSketch = nullptr;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <QObject>
|
||||
#include "ViewportWidget.h" // For SketchPlane enum
|
||||
#include <gp_Pnt.hxx>
|
||||
|
||||
class Document;
|
||||
class MainWindow;
|
||||
@@ -30,6 +31,7 @@ public:
|
||||
|
||||
public slots:
|
||||
void setActiveTool(ToolType tool);
|
||||
void addLine(const gp_Pnt& start, const gp_Pnt& end);
|
||||
void newDocument();
|
||||
bool openDocument();
|
||||
bool saveDocument();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
#include <QPoint>
|
||||
#include <QVector3D>
|
||||
#include <QRect>
|
||||
#include <gp_Pnt.hxx>
|
||||
|
||||
class ViewCube;
|
||||
class SketchGrid;
|
||||
class Document;
|
||||
class FeatureBrowser;
|
||||
class SketchFeature;
|
||||
|
||||
class ViewportWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
||||
{
|
||||
@@ -39,6 +41,7 @@ public:
|
||||
public slots:
|
||||
void onSketchModeStarted(SketchPlane plane);
|
||||
void onSketchModeEnded();
|
||||
void onActiveToolChanged(int tool);
|
||||
|
||||
float xRotation() const;
|
||||
void setXRotation(float angle);
|
||||
@@ -55,6 +58,9 @@ public slots:
|
||||
float panY() const;
|
||||
void setPanY(float value);
|
||||
|
||||
signals:
|
||||
void lineAdded(const gp_Pnt& start, const gp_Pnt& end);
|
||||
|
||||
protected:
|
||||
void initializeGL() override;
|
||||
void paintGL() override;
|
||||
@@ -66,14 +72,22 @@ protected:
|
||||
|
||||
private:
|
||||
QVector3D project(const QVector3D& worldCoord, const QMatrix4x4& modelView, const QMatrix4x4& projection, const QRect& viewport);
|
||||
QVector3D unproject(const QPoint& screenPos);
|
||||
void drawAxisLabels(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection);
|
||||
void drawSketch(const SketchFeature* sketch);
|
||||
|
||||
QMatrix4x4 projection;
|
||||
ViewCube* m_viewCube;
|
||||
SketchGrid* m_sketchGrid = nullptr;
|
||||
FeatureBrowser* m_featureBrowser = nullptr;
|
||||
Document* m_document = nullptr;
|
||||
SketchPlane m_currentPlane = SketchPlane::NONE;
|
||||
|
||||
int m_activeTool = 0;
|
||||
bool m_isDefiningLine = false;
|
||||
gp_Pnt m_firstLinePoint;
|
||||
QPoint m_currentMousePos;
|
||||
|
||||
float m_xRot = 35.264f * 16.0f; // Default to isometric view
|
||||
float m_yRot = -45.0f * 16.0f; // Default to isometric view
|
||||
float m_zoom = -5.0f;
|
||||
|
||||
Reference in New Issue
Block a user