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 "ApplicationController.h"
|
||||||
#include "Document.h"
|
#include "Document.h"
|
||||||
#include "SketchFeature.h"
|
#include "SketchFeature.h"
|
||||||
|
#include "SketchLine.h"
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
|
|
||||||
#include <QInputDialog>
|
#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()
|
void ApplicationController::endSketch()
|
||||||
{
|
{
|
||||||
m_activeSketch = nullptr;
|
m_activeSketch = nullptr;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include "ViewportWidget.h" // For SketchPlane enum
|
#include "ViewportWidget.h" // For SketchPlane enum
|
||||||
|
#include <gp_Pnt.hxx>
|
||||||
|
|
||||||
class Document;
|
class Document;
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
@@ -30,6 +31,7 @@ public:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setActiveTool(ToolType tool);
|
void setActiveTool(ToolType tool);
|
||||||
|
void addLine(const gp_Pnt& start, const gp_Pnt& end);
|
||||||
void newDocument();
|
void newDocument();
|
||||||
bool openDocument();
|
bool openDocument();
|
||||||
bool saveDocument();
|
bool saveDocument();
|
||||||
|
|||||||
@@ -3,6 +3,10 @@
|
|||||||
#include "SketchGrid.h"
|
#include "SketchGrid.h"
|
||||||
#include "Document.h"
|
#include "Document.h"
|
||||||
#include "FeatureBrowser.h"
|
#include "FeatureBrowser.h"
|
||||||
|
#include "SketchFeature.h"
|
||||||
|
#include "SketchLine.h"
|
||||||
|
#include "SketchObject.h"
|
||||||
|
#include "ApplicationController.h"
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QWheelEvent>
|
#include <QWheelEvent>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
@@ -18,6 +22,7 @@ ViewportWidget::ViewportWidget(QWidget *parent)
|
|||||||
m_viewCube = new ViewCube();
|
m_viewCube = new ViewCube();
|
||||||
m_sketchGrid = new SketchGrid();
|
m_sketchGrid = new SketchGrid();
|
||||||
m_featureBrowser = new FeatureBrowser();
|
m_featureBrowser = new FeatureBrowser();
|
||||||
|
setMouseTracking(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewportWidget::~ViewportWidget()
|
ViewportWidget::~ViewportWidget()
|
||||||
@@ -29,6 +34,7 @@ ViewportWidget::~ViewportWidget()
|
|||||||
|
|
||||||
void ViewportWidget::setDocument(Document* document)
|
void ViewportWidget::setDocument(Document* document)
|
||||||
{
|
{
|
||||||
|
m_document = document;
|
||||||
m_featureBrowser->setDocument(document);
|
m_featureBrowser->setDocument(document);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,6 +118,23 @@ void ViewportWidget::paintGL()
|
|||||||
m_sketchGrid->paintGL(static_cast<SketchGrid::SketchPlane>(m_currentPlane), projection, model);
|
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
|
// View cube rendering
|
||||||
QMatrix4x4 viewCubeModel;
|
QMatrix4x4 viewCubeModel;
|
||||||
viewCubeModel.rotate(m_xRot / 16.0f, 1, 0, 0);
|
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)
|
void ViewportWidget::mousePressEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
|
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();
|
lastPos = event->pos();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewportWidget::mouseMoveEvent(QMouseEvent *event)
|
void ViewportWidget::mouseMoveEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
|
m_currentMousePos = event->pos();
|
||||||
int dx = event->pos().x() - lastPos.x();
|
int dx = event->pos().x() - lastPos.x();
|
||||||
int dy = event->pos().y() - lastPos.y();
|
int dy = event->pos().y() - lastPos.y();
|
||||||
|
|
||||||
@@ -150,11 +188,13 @@ void ViewportWidget::mouseMoveEvent(QMouseEvent *event)
|
|||||||
m_panX += dx / 100.0f;
|
m_panX += dx / 100.0f;
|
||||||
m_panY -= dy / 100.0f;
|
m_panY -= dy / 100.0f;
|
||||||
} else {
|
} else {
|
||||||
|
if (m_currentPlane == SketchPlane::NONE) {
|
||||||
// Rotate
|
// Rotate
|
||||||
m_xRot += 8 * dy;
|
m_xRot += 8 * dy;
|
||||||
m_yRot += 8 * dx;
|
m_yRot += 8 * dx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
lastPos = event->pos();
|
lastPos = event->pos();
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
@@ -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 <QPoint>
|
||||||
#include <QVector3D>
|
#include <QVector3D>
|
||||||
#include <QRect>
|
#include <QRect>
|
||||||
|
#include <gp_Pnt.hxx>
|
||||||
|
|
||||||
class ViewCube;
|
class ViewCube;
|
||||||
class SketchGrid;
|
class SketchGrid;
|
||||||
class Document;
|
class Document;
|
||||||
class FeatureBrowser;
|
class FeatureBrowser;
|
||||||
|
class SketchFeature;
|
||||||
|
|
||||||
class ViewportWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
class ViewportWidget : public QOpenGLWidget, protected QOpenGLFunctions
|
||||||
{
|
{
|
||||||
@@ -39,6 +41,7 @@ public:
|
|||||||
public slots:
|
public slots:
|
||||||
void onSketchModeStarted(SketchPlane plane);
|
void onSketchModeStarted(SketchPlane plane);
|
||||||
void onSketchModeEnded();
|
void onSketchModeEnded();
|
||||||
|
void onActiveToolChanged(int tool);
|
||||||
|
|
||||||
float xRotation() const;
|
float xRotation() const;
|
||||||
void setXRotation(float angle);
|
void setXRotation(float angle);
|
||||||
@@ -55,6 +58,9 @@ public slots:
|
|||||||
float panY() const;
|
float panY() const;
|
||||||
void setPanY(float value);
|
void setPanY(float value);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void lineAdded(const gp_Pnt& start, const gp_Pnt& end);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initializeGL() override;
|
void initializeGL() override;
|
||||||
void paintGL() override;
|
void paintGL() override;
|
||||||
@@ -66,14 +72,22 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QVector3D project(const QVector3D& worldCoord, const QMatrix4x4& modelView, const QMatrix4x4& projection, const QRect& viewport);
|
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 drawAxisLabels(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection);
|
||||||
|
void drawSketch(const SketchFeature* sketch);
|
||||||
|
|
||||||
QMatrix4x4 projection;
|
QMatrix4x4 projection;
|
||||||
ViewCube* m_viewCube;
|
ViewCube* m_viewCube;
|
||||||
SketchGrid* m_sketchGrid = nullptr;
|
SketchGrid* m_sketchGrid = nullptr;
|
||||||
FeatureBrowser* m_featureBrowser = nullptr;
|
FeatureBrowser* m_featureBrowser = nullptr;
|
||||||
|
Document* m_document = nullptr;
|
||||||
SketchPlane m_currentPlane = SketchPlane::NONE;
|
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_xRot = 35.264f * 16.0f; // Default to isometric view
|
||||||
float m_yRot = -45.0f * 16.0f; // Default to isometric view
|
float m_yRot = -45.0f * 16.0f; // Default to isometric view
|
||||||
float m_zoom = -5.0f;
|
float m_zoom = -5.0f;
|
||||||
|
|||||||
Reference in New Issue
Block a user