Compare commits

19 Commits

Author SHA1 Message Date
tanner 4f1a8b22ac fix: Update ElCLib 2D/3D point conversion API in ViewportWidget
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 16:36:07 -07:00
tanner 1b1d2eab11 fix: Remove redeclaration of lineDirGp and lineDir2d
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 16:34:40 -07:00
tanner 6d92349938 fix: Update Open CASCADE point conversion API in ApplicationController
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 16:33:21 -07:00
tanner aa8127c5f8 fix: Update OpenCASCADE 2D/3D point conversion API in Snapping
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 16:31:33 -07:00
tanner b75e355698 fix: Update OpenCASCADE API usage for 2D/3D geometry conversion
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 16:30:13 -07:00
tanner 4cebb8d552 fix: Adapt RectangleTool to updated Open CASCADE ElCLib API
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 16:25:59 -07:00
tanner d7e9d784cc fix: Correct ElCLib 2D/3D conversion function calls
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 16:22:31 -07:00
tanner f942a424f3 fix: Correct ElCLib point conversion function names
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 16:20:07 -07:00
tanner e37959ca89 refactor: Eliminate SketchPlane enum, use gp_Ax2 for all plane operations
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 16:18:36 -07:00
tanner 64ff7396c2 refactor: Use gp_Ax2 for camera plane orientation
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 16:09:38 -07:00
tanner 79c78f0601 refactor: Refactor LineTool to use gp_Ax2 for sketch plane operations
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 16:07:13 -07:00
tanner 96371b0aa6 refactor: Use gp_Ax2 for geometric calculations in RectangleTool
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 16:02:18 -07:00
tanner e363595eb5 refactor: Use gp_Ax2 for all sketch plane calculations in CircleTool
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 15:58:17 -07:00
tanner 228540e095 refactor: Use gp_Ax2 for plane-agnostic snapping calculations and rendering
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 15:54:29 -07:00
tanner e960c30b48 refactor: Use gp_Ax2 to define and draw SketchGrid planes
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 15:51:43 -07:00
tanner 0469853a2c refactor: Adopt gp_Ax2 for sketch plane and geometry definition
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 15:46:26 -07:00
tanner 577fb5f846 refactor: Use gp_Ax2 for sketch plane definition and drawing
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 15:44:13 -07:00
tanner 08904feb1e fix: Resolve type mismatch when adding wire to sketch
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 15:31:45 -07:00
tanner 125e97df50 feat: Create Open CASCADE shapes for sketch geometry
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
2026-03-03 15:30:01 -07:00
14 changed files with 955 additions and 936 deletions
+44 -16
View File
@@ -13,6 +13,16 @@
#include "SketchCircle.h" #include "SketchCircle.h"
#include "MainWindow.h" #include "MainWindow.h"
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <GC_MakeSegment.hxx>
#include <ElCLib.hxx>
#include <gp_Ax2.hxx>
#include <gp_Circ.hxx>
#include <gp_Dir.hxx>
#include <gp_Vec.hxx>
#include <gp_Pnt2d.hxx>
#include <QInputDialog> #include <QInputDialog>
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox> #include <QMessageBox>
@@ -117,26 +127,12 @@ void ApplicationController::beginSketchCreation()
emit planeSelectionModeStarted(); emit planeSelectionModeStarted();
} }
void ApplicationController::onPlaneSelected(ViewportWidget::SketchPlane plane) void ApplicationController::onPlaneSelected(const gp_Ax2& plane)
{ {
auto feature = new SketchFeature("Sketch"); auto feature = new SketchFeature("Sketch");
m_activeSketch = feature; m_activeSketch = feature;
switch (plane) { feature->setPlane(plane);
case ViewportWidget::SketchPlane::XY:
feature->setPlane(SketchFeature::SketchPlane::XY);
break;
case ViewportWidget::SketchPlane::XZ:
feature->setPlane(SketchFeature::SketchPlane::XZ);
break;
case ViewportWidget::SketchPlane::YZ:
feature->setPlane(SketchFeature::SketchPlane::YZ);
break;
case ViewportWidget::SketchPlane::NONE:
delete feature;
m_activeSketch = nullptr;
return;
}
m_document->addFeature(feature); m_document->addFeature(feature);
emit sketchModeStarted(plane); emit sketchModeStarted(plane);
@@ -146,6 +142,10 @@ void ApplicationController::addLine(const gp_Pnt& start, const gp_Pnt& end)
{ {
if (m_activeSketch) { if (m_activeSketch) {
m_activeSketch->addObject(new SketchLine(start, end)); m_activeSketch->addObject(new SketchLine(start, end));
Handle(Geom_TrimmedCurve) segment = GC_MakeSegment(start, end);
TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(segment);
m_activeSketch->addShape(edge);
} }
} }
@@ -153,6 +153,27 @@ void ApplicationController::addRectangle(const gp_Pnt& corner1, const gp_Pnt& co
{ {
if (m_activeSketch) { if (m_activeSketch) {
m_activeSketch->addObject(new SketchRectangle(corner1, corner2)); m_activeSketch->addObject(new SketchRectangle(corner1, corner2));
const auto& plane = m_activeSketch->plane();
gp_Pnt2d p1_2d(gp_Vec(plane.Location(), corner1).Dot(plane.XDirection()), gp_Vec(plane.Location(), corner1).Dot(plane.YDirection()));
gp_Pnt2d p3_2d(gp_Vec(plane.Location(), corner2).Dot(plane.XDirection()), gp_Vec(plane.Location(), corner2).Dot(plane.YDirection()));
gp_Pnt2d p2_2d(p3_2d.X(), p1_2d.Y());
gp_Pnt2d p4_2d(p1_2d.X(), p3_2d.Y());
gp_Pnt p2_3d = ElCLib::To3d(plane, p2_2d);
gp_Pnt p4_3d = ElCLib::To3d(plane, p4_2d);
TopoDS_Edge e1 = BRepBuilderAPI_MakeEdge(corner1, p2_3d);
TopoDS_Edge e2 = BRepBuilderAPI_MakeEdge(p2_3d, corner2);
TopoDS_Edge e3 = BRepBuilderAPI_MakeEdge(corner2, p4_3d);
TopoDS_Edge e4 = BRepBuilderAPI_MakeEdge(p4_3d, corner1);
BRepBuilderAPI_MakeWire wireMaker(e1, e2, e3, e4);
if (wireMaker.IsDone()) {
m_activeSketch->addShape(wireMaker.Shape());
}
} }
} }
@@ -160,6 +181,13 @@ void ApplicationController::addCircle(const gp_Pnt& center, double radius)
{ {
if (m_activeSketch) { if (m_activeSketch) {
m_activeSketch->addObject(new SketchCircle(center, radius)); m_activeSketch->addObject(new SketchCircle(center, radius));
const auto& sketchPlane = m_activeSketch->plane();
gp_Ax2 axis(center, sketchPlane.Direction());
gp_Circ circle(axis, radius);
TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(circle);
m_activeSketch->addShape(edge);
} }
} }
+3 -3
View File
@@ -9,8 +9,8 @@
#define APPLICATIONCONTROLLER_H #define APPLICATIONCONTROLLER_H
#include <QObject> #include <QObject>
#include "ViewportWidget.h" // For SketchPlane enum
#include <gp_Pnt.hxx> #include <gp_Pnt.hxx>
#include <gp_Ax2.hxx>
class Document; class Document;
class MainWindow; class MainWindow;
@@ -47,12 +47,12 @@ public slots:
bool saveDocumentAs(); bool saveDocumentAs();
void beginSketchCreation(); void beginSketchCreation();
void onPlaneSelected(ViewportWidget::SketchPlane plane); void onPlaneSelected(const gp_Ax2& plane);
void endSketch(); void endSketch();
signals: signals:
void planeSelectionModeStarted(); void planeSelectionModeStarted();
void sketchModeStarted(ViewportWidget::SketchPlane plane); void sketchModeStarted(const gp_Ax2& plane);
void sketchModeEnded(); void sketchModeEnded();
void currentFileChanged(const QString& path); void currentFileChanged(const QString& path);
void activeToolChanged(ToolType tool); void activeToolChanged(ToolType tool);
+23 -19
View File
@@ -6,7 +6,8 @@
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
#include "Camera.h" #include "Camera.h"
#include "ViewportWidget.h" #include <gp_Ax2.hxx>
#include <gp_Dir.hxx>
#include <QApplication> #include <QApplication>
#include <QWheelEvent> #include <QWheelEvent>
#include <QPropertyAnimation> #include <QPropertyAnimation>
@@ -202,25 +203,28 @@ void Camera::restoreState()
setZoom(m_savedZoom); setZoom(m_savedZoom);
} }
void Camera::animateToPlaneView(int plane) void Camera::animateToPlaneView(const gp_Ax2& plane)
{ {
float targetXRot = xRotation(); const auto& normal = plane.Direction();
float targetYRot = yRotation(); QVector3D n(normal.X(), normal.Y(), normal.Z());
switch (static_cast<ViewportWidget::SketchPlane>(plane)) { QVector3D d;
case ViewportWidget::SketchPlane::XY: // Top view
targetXRot = 90 * 16; // This logic preserves the quirky view directions of the original implementation.
targetYRot = 0; // For XZ-like planes (normal is mostly along Y), the view is aligned WITH the plane normal.
break; // For other planes, it's aligned AGAINST the normal.
case ViewportWidget::SketchPlane::XZ: // Front view if (qAbs(n.y()) > 0.99) {
targetXRot = 0; d = n;
targetYRot = 0; } else {
break; d = -n;
case ViewportWidget::SketchPlane::YZ: // Right view }
targetXRot = 0;
targetYRot = -90 * 16; float targetXRot = qRadiansToDegrees(asin(-d.z())) * 16.0f;
break; float targetYRot;
case ViewportWidget::SketchPlane::NONE:
break; if (qAbs(d.z()) > 0.9999) { // Top/bottom-like view, Y rotation is arbitrary
targetYRot = 0; // Set to 0 for stability
} else {
targetYRot = qRadiansToDegrees(atan2(d.x(), d.y())) * 16.0f;
} }
auto* animGroup = new QParallelAnimationGroup(this); auto* animGroup = new QParallelAnimationGroup(this);
+3 -1
View File
@@ -14,6 +14,8 @@
#include <QMouseEvent> #include <QMouseEvent>
#include <QWheelEvent> #include <QWheelEvent>
#include <gp_Ax2.hxx>
class Camera : public QObject class Camera : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -46,7 +48,7 @@ public:
void saveState(); void saveState();
void restoreState(); void restoreState();
void animateToPlaneView(int plane); void animateToPlaneView(const gp_Ax2& plane);
void animateRestoreState(); void animateRestoreState();
void animateToHomeView(); void animateToHomeView();
+125 -131
View File
@@ -15,6 +15,10 @@
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <cmath> #include <cmath>
#include <QtMath> #include <QtMath>
#include <optional>
#include <gp_Ax2.hxx>
#include <gp_Pnt2d.hxx>
#include <ElCLib.hxx>
CircleTool::CircleTool(ViewportWidget* viewport) CircleTool::CircleTool(ViewportWidget* viewport)
: SketchTool(viewport) : SketchTool(viewport)
@@ -35,14 +39,18 @@ void CircleTool::activate()
void CircleTool::mousePressEvent(QMouseEvent *event) void CircleTool::mousePressEvent(QMouseEvent *event)
{ {
auto currentPlaneOpt = m_viewport->currentPlane();
if (!currentPlaneOpt) return;
const auto& plane = currentPlaneOpt.value();
gp_Pnt p; gp_Pnt p;
if (!m_isDefining) { if (!m_isDefining) {
if (m_viewport->isSnappingOrigin()) { if (m_viewport->isSnappingOrigin()) {
p.SetCoord(0, 0, 0); p = plane.Location();
} else if (m_viewport->isSnappingVertex()) { } else if (m_viewport->isSnappingVertex()) {
p = m_viewport->snapVertex(); p = m_viewport->snapVertex();
} else { } else {
QVector3D worldPos = m_viewport->unproject(event->pos(), m_viewport->currentPlane()); QVector3D worldPos = m_viewport->unproject(event->pos(), plane);
p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z()); p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z());
} }
m_centerPoint = p; m_centerPoint = p;
@@ -70,24 +78,22 @@ void CircleTool::mousePressEvent(QMouseEvent *event)
} }
if (diameterFromInput) { if (diameterFromInput) {
QVector3D mousePos = m_viewport->unproject(event->pos(), m_viewport->currentPlane()); QVector3D mousePos = m_viewport->unproject(event->pos(), plane);
QVector3D mouseDir = mousePos - centerPos; QVector3D mouseDir = mousePos - centerPos;
if (mouseDir.lengthSquared() < 1e-9) { if (mouseDir.lengthSquared() < 1e-9) {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { const auto& xDir = plane.XDirection();
mouseDir = QVector3D(1, 0, 0); mouseDir = QVector3D(xDir.X(), xDir.Y(), xDir.Z());
} else { // YZ
mouseDir = QVector3D(0, 1, 0);
}
} }
double radius = inputDiameter / 2.0; double radius = inputDiameter / 2.0;
worldPos = centerPos + mouseDir.normalized() * radius; worldPos = centerPos + mouseDir.normalized() * radius;
} else { } else {
if (m_viewport->isSnappingOrigin()) { if (m_viewport->isSnappingOrigin()) {
worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0); const auto& origin = plane.Location();
worldPos.setX(origin.X()); worldPos.setY(origin.Y()); worldPos.setZ(origin.Z());
} else if (m_viewport->isSnappingVertex()) { } else if (m_viewport->isSnappingVertex()) {
worldPos = QVector3D(m_viewport->snapVertex().X(), m_viewport->snapVertex().Y(), m_viewport->snapVertex().Z()); worldPos = QVector3D(m_viewport->snapVertex().X(), m_viewport->snapVertex().Y(), m_viewport->snapVertex().Z());
} else { } else {
worldPos = m_viewport->unproject(event->pos(), m_viewport->currentPlane()); worldPos = m_viewport->unproject(event->pos(), plane);
} }
} }
p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z()); p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z());
@@ -103,6 +109,10 @@ void CircleTool::mouseMoveEvent(QMouseEvent *event)
void CircleTool::finalizeCreation() void CircleTool::finalizeCreation()
{ {
auto currentPlaneOpt = m_viewport->currentPlane();
if (!currentPlaneOpt) return;
const auto& plane = currentPlaneOpt.value();
QVector3D worldPos; QVector3D worldPos;
QVector3D centerPos(m_centerPoint.X(), m_centerPoint.Y(), m_centerPoint.Z()); QVector3D centerPos(m_centerPoint.X(), m_centerPoint.Y(), m_centerPoint.Z());
@@ -117,19 +127,16 @@ void CircleTool::finalizeCreation()
} }
if (diameterFromInput) { if (diameterFromInput) {
QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), plane);
QVector3D mouseDir = mousePos - centerPos; QVector3D mouseDir = mousePos - centerPos;
if (mouseDir.lengthSquared() < 1e-9) { if (mouseDir.lengthSquared() < 1e-9) {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { const auto& xDir = plane.XDirection();
mouseDir = QVector3D(1, 0, 0); mouseDir = QVector3D(xDir.X(), xDir.Y(), xDir.Z());
} else { // YZ
mouseDir = QVector3D(0, 1, 0);
}
} }
double radius = inputDiameter / 2.0; double radius = inputDiameter / 2.0;
worldPos = centerPos + mouseDir.normalized() * radius; worldPos = centerPos + mouseDir.normalized() * radius;
} else { } else {
worldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); worldPos = m_viewport->unproject(m_viewport->currentMousePos(), plane);
} }
gp_Pnt p; gp_Pnt p;
@@ -141,134 +148,121 @@ void CircleTool::finalizeCreation()
void CircleTool::paintGL() void CircleTool::paintGL()
{ {
if (m_isDefining) { auto currentPlaneOpt = m_viewport->currentPlane();
QVector<GLfloat> vertices; if (!m_isDefining || !currentPlaneOpt) return;
QVector3D worldPos; const auto& plane = currentPlaneOpt.value();
QVector3D centerPos(m_centerPoint.X(), m_centerPoint.Y(), m_centerPoint.Z());
QString diameterInput = m_viewport->property("diameterInput").toString(); QVector<GLfloat> vertices;
bool diameterFromInput = false; QVector3D worldPos;
double inputDiameter = 0; QVector3D centerPos(m_centerPoint.X(), m_centerPoint.Y(), m_centerPoint.Z());
if (!diameterInput.isEmpty()) { QString diameterInput = m_viewport->property("diameterInput").toString();
bool ok; bool diameterFromInput = false;
inputDiameter = diameterInput.toDouble(&ok); double inputDiameter = 0;
if (ok) diameterFromInput = true;
}
QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); if (!diameterInput.isEmpty()) {
bool ok;
double radius; inputDiameter = diameterInput.toDouble(&ok);
if (diameterFromInput) { if (ok) diameterFromInput = true;
radius = inputDiameter / 2.0;
} 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());
}
radius = (worldPos - centerPos).length();
}
const int segments = 64;
for (int i = 0; i < segments; ++i) {
double angle1 = i * 2.0 * M_PI / segments;
double angle2 = (i + 1) * 2.0 * M_PI / segments;
QVector3D p1, p2;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
p1.setX(centerPos.x() + radius * qCos(angle1));
p1.setY(centerPos.y() + radius * qSin(angle1));
p1.setZ(centerPos.z());
p2.setX(centerPos.x() + radius * qCos(angle2));
p2.setY(centerPos.y() + radius * qSin(angle2));
p2.setZ(centerPos.z());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
p1.setX(centerPos.x() + radius * qCos(angle1));
p1.setY(centerPos.y());
p1.setZ(centerPos.z() + radius * qSin(angle1));
p2.setX(centerPos.x() + radius * qCos(angle2));
p2.setY(centerPos.y());
p2.setZ(centerPos.z() + radius * qSin(angle2));
} else { // YZ
p1.setX(centerPos.x());
p1.setY(centerPos.y() + radius * qCos(angle1));
p1.setZ(centerPos.z() + radius * qSin(angle1));
p2.setX(centerPos.x());
p2.setY(centerPos.y() + radius * qCos(angle2));
p2.setZ(centerPos.z() + radius * qSin(angle2));
}
vertices << p1.x() << p1.y() << p1.z();
vertices << p2.x() << p2.y() << p2.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, segments * 2);
} }
QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), plane);
double radius;
if (diameterFromInput) {
radius = inputDiameter / 2.0;
} else {
worldPos = mousePos;
if (m_viewport->isSnappingOrigin()) {
const auto& origin = plane.Location();
worldPos.setX(origin.X()); worldPos.setY(origin.Y()); worldPos.setZ(origin.Z());
} else if (m_viewport->isSnappingVertex()) {
worldPos.setX(m_viewport->snapVertex().X()); worldPos.setY(m_viewport->snapVertex().Y()); worldPos.setZ(m_viewport->snapVertex().Z());
}
radius = (worldPos - centerPos).length();
}
const int segments = 64;
const auto& xDir = plane.XDirection();
const auto& yDir = plane.YDirection();
QVector3D u_axis(xDir.X(), xDir.Y(), xDir.Z());
QVector3D v_axis(yDir.X(), yDir.Y(), yDir.Z());
for (int i = 0; i < segments; ++i) {
double angle1 = i * 2.0 * M_PI / segments;
double angle2 = (i + 1) * 2.0 * M_PI / segments;
QVector3D p1 = centerPos + radius * (qCos(angle1) * u_axis + qSin(angle1) * v_axis);
QVector3D p2 = centerPos + radius * (qCos(angle2) * u_axis + qSin(angle2) * v_axis);
vertices << p1.x() << p1.y() << p1.z();
vertices << p2.x() << p2.y() << p2.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, segments * 2);
} }
void CircleTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection) void CircleTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection)
{ {
if (m_isDefining) { auto currentPlaneOpt = m_viewport->currentPlane();
QVector3D worldPos; if (!m_isDefining || !currentPlaneOpt) return;
QVector3D centerPos(m_centerPoint.X(), m_centerPoint.Y(), m_centerPoint.Z()); const auto& plane = currentPlaneOpt.value();
QString diameterInput = m_viewport->property("diameterInput").toString(); QVector3D worldPos;
bool diameterFromInput = false; QVector3D centerPos(m_centerPoint.X(), m_centerPoint.Y(), m_centerPoint.Z());
double inputDiameter = 0;
if (!diameterInput.isEmpty()) { QString diameterInput = m_viewport->property("diameterInput").toString();
bool ok; bool diameterFromInput = false;
inputDiameter = diameterInput.toDouble(&ok); double inputDiameter = 0;
if (ok) diameterFromInput = true;
if (!diameterInput.isEmpty()) {
bool ok;
inputDiameter = diameterInput.toDouble(&ok);
if (ok) diameterFromInput = true;
}
QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), plane);
QVector3D edgePos;
double diameter;
if (diameterFromInput) {
diameter = inputDiameter;
QVector3D mouseDir = mousePos - centerPos;
if (mouseDir.lengthSquared() < 1e-9) {
const auto& xDir = plane.XDirection();
mouseDir = QVector3D(xDir.X(), xDir.Y(), xDir.Z());
} }
edgePos = centerPos + mouseDir.normalized() * (diameter / 2.0);
} else {
edgePos = mousePos;
if (m_viewport->isSnappingOrigin()) {
const auto& origin = plane.Location();
edgePos.setX(origin.X()); edgePos.setY(origin.Y()); edgePos.setZ(origin.Z());
} else if (m_viewport->isSnappingVertex()) {
edgePos.setX(m_viewport->snapVertex().X()); edgePos.setY(m_viewport->snapVertex().Y()); edgePos.setZ(m_viewport->snapVertex().Z());
}
diameter = (edgePos - centerPos).length() * 2.0;
}
QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); painter.setRenderHint(QPainter::Antialiasing);
QVector3D edgePos; QFontMetrics fm(painter.font());
double diameter;
if (diameterFromInput) { // Diameter dimension
diameter = inputDiameter; QVector3D diameterTextPos3D = (centerPos + edgePos) / 2.0f;
QVector3D mouseDir = mousePos - centerPos; QVector3D screenPosD = m_viewport->project(diameterTextPos3D, modelView, projection, m_viewport->rect());
if (mouseDir.lengthSquared() < 1e-9) { if (screenPosD.z() < 1.0f) {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { QString diameterText = diameterFromInput ? diameterInput : QString::number(diameter, 'f', 2);
mouseDir = QVector3D(1, 0, 0); QRect textRect = fm.boundingRect(diameterText + "__");
} else { // YZ textRect.moveCenter(screenPosD.toPoint());
mouseDir = QVector3D(0, 1, 0); if (m_viewport->property("dimensionEditMode").toString() == "diameter") {
} painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(64, 128, 255));
}
edgePos = centerPos + mouseDir.normalized() * (diameter / 2.0);
} else { } else {
edgePos = mousePos; painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(50, 50, 50));
if (m_viewport->isSnappingOrigin()) {
edgePos.setX(0); edgePos.setY(0); edgePos.setZ(0);
} else if (m_viewport->isSnappingVertex()) {
edgePos.setX(m_viewport->snapVertex().X()); edgePos.setY(m_viewport->snapVertex().Y()); edgePos.setZ(m_viewport->snapVertex().Z());
}
diameter = (edgePos - centerPos).length() * 2.0;
}
painter.setRenderHint(QPainter::Antialiasing);
QFontMetrics fm(painter.font());
// Diameter dimension
QVector3D diameterTextPos3D = (centerPos + edgePos) / 2.0f;
QVector3D screenPosD = m_viewport->project(diameterTextPos3D, modelView, projection, m_viewport->rect());
if (screenPosD.z() < 1.0f) {
QString diameterText = diameterFromInput ? diameterInput : QString::number(diameter, 'f', 2);
QRect textRect = fm.boundingRect(diameterText + "__");
textRect.moveCenter(screenPosD.toPoint());
if (m_viewport->property("dimensionEditMode").toString() == "diameter") {
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, diameterText);
} }
painter.setPen(Qt::white);
painter.drawText(textRect, Qt::AlignCenter, diameterText);
} }
} }
+241 -236
View File
@@ -13,6 +13,13 @@
#include <QPainter> #include <QPainter>
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QtMath> #include <QtMath>
#include <optional>
#include <gp_Ax2.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Dir2d.hxx>
#include <gp_Vec2d.hxx>
#include <gp_Vec.hxx>
#include <ElCLib.hxx>
LineTool::LineTool(ViewportWidget* viewport) LineTool::LineTool(ViewportWidget* viewport)
: SketchTool(viewport) : SketchTool(viewport)
@@ -34,6 +41,10 @@ void LineTool::activate()
void LineTool::mousePressEvent(QMouseEvent *event) void LineTool::mousePressEvent(QMouseEvent *event)
{ {
auto currentPlaneOpt = m_viewport->currentPlane();
if (!currentPlaneOpt) return;
const auto& plane = currentPlaneOpt.value();
gp_Pnt p; gp_Pnt p;
QString dimInput = m_viewport->property("dimensionInput").toString(); QString dimInput = m_viewport->property("dimensionInput").toString();
QString angleInput = m_viewport->property("angleInput").toString(); QString angleInput = m_viewport->property("angleInput").toString();
@@ -64,19 +75,23 @@ void LineTool::mousePressEvent(QMouseEvent *event)
if (m_viewport->property("isChainedLine").toBool()) { if (m_viewport->property("isChainedLine").toBool()) {
refDir = m_viewport->property("previousLineDirection").value<QVector3D>(); refDir = m_viewport->property("previousLineDirection").value<QVector3D>();
} else { } else {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refDir = QVector3D(1, 0, 0); const auto& xDir = plane.XDirection();
else refDir = QVector3D(0, 1, 0); refDir = QVector3D(xDir.X(), xDir.Y(), xDir.Z());
} }
QVector3D currentMouseWorldPos = m_viewport->unproject(event->pos(), m_viewport->currentPlane()); QVector3D currentMouseWorldPos = m_viewport->unproject(event->pos(), plane);
QVector3D mouseVec = currentMouseWorldPos - startPos; QVector3D mouseVec = currentMouseWorldPos - startPos;
double mouseAngle;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVec.y(), mouseVec.x())); gp_Pnt startPnt(startPos.x(), startPos.y(), startPos.z());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.x())); gp_Pnt mousePnt(currentMouseWorldPos.x(), currentMouseWorldPos.y(), currentMouseWorldPos.z());
else mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.y())); gp_Dir refDirGp(refDir.x(), refDir.y(), refDir.z());
double refAngle;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) refAngle = qRadiansToDegrees(atan2(refDir.y(), refDir.x())); gp_Pnt2d startPnt2d(gp_Vec(plane.Location(), startPnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), startPnt).Dot(plane.YDirection()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.x())); gp_Pnt2d mousePnt2d(gp_Vec(plane.Location(), mousePnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), mousePnt).Dot(plane.YDirection()));
else refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.y())); gp_Dir2d refDir2d(refDirGp.Dot(plane.XDirection()), refDirGp.Dot(plane.YDirection()));
gp_Vec2d mouseVec2d(startPnt2d, mousePnt2d);
double mouseAngle = qRadiansToDegrees(atan2(mouseVec2d.Y(), mouseVec2d.X()));
double refAngle = qRadiansToDegrees(atan2(refDir2d.Y(), refDir2d.X()));
double relativeMouseAngle = mouseAngle - refAngle; double relativeMouseAngle = mouseAngle - refAngle;
while (relativeMouseAngle <= -180.0) relativeMouseAngle += 360.0; while (relativeMouseAngle <= -180.0) relativeMouseAngle += 360.0;
while (relativeMouseAngle > 180.0) relativeMouseAngle -= 360.0; while (relativeMouseAngle > 180.0) relativeMouseAngle -= 360.0;
@@ -91,10 +106,9 @@ void LineTool::mousePressEvent(QMouseEvent *event)
snappedAngle = -inputAngleDegrees; snappedAngle = -inputAngleDegrees;
} }
double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle); double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle);
QVector3D finalDir; gp_Dir2d finalDir2d(cos(finalAngleRad), sin(finalAngleRad));
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) finalDir = QVector3D(cos(finalAngleRad), sin(finalAngleRad), 0); gp_Dir finalDir3d = ElCLib::To3d(plane, finalDir2d);
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) finalDir = QVector3D(cos(finalAngleRad), 0, sin(finalAngleRad)); QVector3D finalDir(finalDir3d.X(), finalDir3d.Y(), finalDir3d.Z());
else finalDir = QVector3D(0, cos(finalAngleRad), sin(finalAngleRad));
double lineLength; double lineLength;
if (lengthFromInput) lineLength = inputLength; if (lengthFromInput) lineLength = inputLength;
else { else {
@@ -103,34 +117,37 @@ void LineTool::mousePressEvent(QMouseEvent *event)
} }
worldPos = startPos + lineLength * finalDir; worldPos = startPos + lineLength * finalDir;
} else if (lengthFromInput) { } else if (lengthFromInput) {
QVector3D currentMouseWorldPos = m_viewport->unproject(event->pos(), m_viewport->currentPlane()); QVector3D currentMouseWorldPos = m_viewport->unproject(event->pos(), plane);
QVector3D dir = (currentMouseWorldPos - startPos); QVector3D dir = (currentMouseWorldPos - startPos);
if (dir.length() > 1e-6) { if (dir.length() > 1e-6) {
dir.normalize(); dir.normalize();
worldPos = startPos + inputLength * dir; worldPos = startPos + inputLength * dir;
} else { } else {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos = startPos + QVector3D(inputLength, 0, 0); const auto& xDir = plane.XDirection();
else worldPos = startPos + QVector3D(0, inputLength, 0); worldPos = startPos + inputLength * QVector3D(xDir.X(), xDir.Y(), xDir.Z());
} }
} }
p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z()); p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z());
} else { } else {
if (m_viewport->isSnappingOrigin()) { if (m_viewport->isSnappingOrigin()) {
p.SetCoord(0, 0, 0); p = plane.Location();
} else if (m_viewport->isSnappingVertex()) { } else if (m_viewport->isSnappingVertex()) {
p = m_viewport->snapVertex(); p = m_viewport->snapVertex();
} else { } else {
QVector3D worldPos = m_viewport->unproject(event->pos(), m_viewport->currentPlane()); QVector3D worldPosQ = m_viewport->unproject(event->pos(), plane);
if (m_viewport->isSnappingHorizontal()) { gp_Pnt worldPos(worldPosQ.x(), worldPosQ.y(), worldPosQ.z());
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setY(m_firstLinePoint.Y());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos.setZ(m_firstLinePoint.Z()); if (m_viewport->isSnappingHorizontal() || m_viewport->isSnappingVertical()) {
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) worldPos.setZ(m_firstLinePoint.Z()); gp_Pnt2d worldPos2d(gp_Vec(plane.Location(), worldPos).Dot(plane.XDirection()), gp_Vec(plane.Location(), worldPos).Dot(plane.YDirection()));
} else if (m_viewport->isSnappingVertical()) { gp_Pnt2d firstPoint2d(gp_Vec(plane.Location(), m_firstLinePoint).Dot(plane.XDirection()), gp_Vec(plane.Location(), m_firstLinePoint).Dot(plane.YDirection()));
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setX(m_firstLinePoint.X()); if (m_viewport->isSnappingHorizontal()) {
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos.setX(m_firstLinePoint.X()); worldPos2d.SetY(firstPoint2d.Y());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) worldPos.setY(m_firstLinePoint.Y()); } else { // vertical
worldPos2d.SetX(firstPoint2d.X());
}
worldPos = ElCLib::To3d(plane, worldPos2d);
} }
p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z()); p = worldPos;
} }
} }
@@ -157,27 +174,27 @@ void LineTool::mousePressEvent(QMouseEvent *event)
void LineTool::mouseMoveEvent(QMouseEvent *event) void LineTool::mouseMoveEvent(QMouseEvent *event)
{ {
auto currentPlaneOpt = m_viewport->currentPlane();
if (!m_isDefining || !currentPlaneOpt) return;
const auto& plane = currentPlaneOpt.value();
bool oldIsSnappingHorizontal = m_viewport->isSnappingHorizontal(); bool oldIsSnappingHorizontal = m_viewport->isSnappingHorizontal();
bool oldIsSnappingVertical = m_viewport->isSnappingVertical(); bool oldIsSnappingVertical = m_viewport->isSnappingVertical();
m_viewport->setSnappingHorizontal(false); m_viewport->setSnappingHorizontal(false);
m_viewport->setSnappingVertical(false); m_viewport->setSnappingVertical(false);
if (m_isDefining && !m_viewport->isSnappingOrigin() && !m_viewport->isSnappingVertex()) { if (m_isDefining && !m_viewport->isSnappingOrigin() && !m_viewport->isSnappingVertex()) {
QVector3D worldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); QVector3D worldPosQ = m_viewport->unproject(m_viewport->currentMousePos(), plane);
QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z()); gp_Pnt worldPos(worldPosQ.x(), worldPosQ.y(), worldPosQ.z());
QVector3D delta = worldPos - startPos; gp_Pnt startPos = m_firstLinePoint;
if (delta.length() > 1e-6) { gp_Pnt2d worldPos2d(gp_Vec(plane.Location(), worldPos).Dot(plane.XDirection()), gp_Vec(plane.Location(), worldPos).Dot(plane.YDirection()));
gp_Pnt2d startPos2d(gp_Vec(plane.Location(), startPos).Dot(plane.XDirection()), gp_Vec(plane.Location(), startPos).Dot(plane.YDirection()));
gp_Vec2d delta(startPos2d, worldPos2d);
if (delta.Magnitude() > 1e-6) {
const double snapAngleThreshold = qDegreesToRadians(2.0); const double snapAngleThreshold = qDegreesToRadians(2.0);
double angle = 0; double angle = atan2(delta.Y(), delta.X());
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
angle = atan2(delta.y(), delta.x());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
angle = atan2(delta.z(), delta.x());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) {
angle = atan2(delta.z(), delta.y());
}
if (qAbs(sin(angle)) < sin(snapAngleThreshold)) { if (qAbs(sin(angle)) < sin(snapAngleThreshold)) {
m_viewport->setSnappingHorizontal(true); m_viewport->setSnappingHorizontal(true);
@@ -194,6 +211,10 @@ void LineTool::mouseMoveEvent(QMouseEvent *event)
void LineTool::finalizeCreation() void LineTool::finalizeCreation()
{ {
auto currentPlaneOpt = m_viewport->currentPlane();
if (!currentPlaneOpt) return;
const auto& plane = currentPlaneOpt.value();
QVector3D worldPos; QVector3D worldPos;
QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z()); QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
// This is duplicated from paintGL to ensure consistent line creation // This is duplicated from paintGL to ensure consistent line creation
@@ -220,19 +241,23 @@ void LineTool::finalizeCreation()
if (m_viewport->property("isChainedLine").toBool()) { if (m_viewport->property("isChainedLine").toBool()) {
refDir = m_viewport->property("previousLineDirection").value<QVector3D>(); refDir = m_viewport->property("previousLineDirection").value<QVector3D>();
} else { } else {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refDir = QVector3D(1, 0, 0); const auto& xDir = plane.XDirection();
else refDir = QVector3D(0, 1, 0); refDir = QVector3D(xDir.X(), xDir.Y(), xDir.Z());
} }
QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), plane);
QVector3D mouseVec = currentMouseWorldPos - startPos; QVector3D mouseVec = currentMouseWorldPos - startPos;
double mouseAngle;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVec.y(), mouseVec.x())); gp_Pnt startPnt(startPos.x(), startPos.y(), startPos.z());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.x())); gp_Pnt mousePnt(currentMouseWorldPos.x(), currentMouseWorldPos.y(), currentMouseWorldPos.z());
else mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.y())); gp_Dir refDirGp(refDir.x(), refDir.y(), refDir.z());
double refAngle;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) refAngle = qRadiansToDegrees(atan2(refDir.y(), refDir.x())); gp_Pnt2d startPnt2d(gp_Vec(plane.Location(), startPnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), startPnt).Dot(plane.YDirection()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.x())); gp_Pnt2d mousePnt2d(gp_Vec(plane.Location(), mousePnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), mousePnt).Dot(plane.YDirection()));
else refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.y())); gp_Dir2d refDir2d(refDirGp.Dot(plane.XDirection()), refDirGp.Dot(plane.YDirection()));
gp_Vec2d mouseVec2d(startPnt2d, mousePnt2d);
double mouseAngle = qRadiansToDegrees(atan2(mouseVec2d.Y(), mouseVec2d.X()));
double refAngle = qRadiansToDegrees(atan2(refDir2d.Y(), refDir2d.X()));
double relativeMouseAngle = mouseAngle - refAngle; double relativeMouseAngle = mouseAngle - refAngle;
while (relativeMouseAngle <= -180.0) relativeMouseAngle += 360.0; while (relativeMouseAngle <= -180.0) relativeMouseAngle += 360.0;
while (relativeMouseAngle > 180.0) relativeMouseAngle -= 360.0; while (relativeMouseAngle > 180.0) relativeMouseAngle -= 360.0;
@@ -247,10 +272,9 @@ void LineTool::finalizeCreation()
snappedAngle = -inputAngleDegrees; snappedAngle = -inputAngleDegrees;
} }
double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle); double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle);
QVector3D finalDir; gp_Dir2d finalDir2d(cos(finalAngleRad), sin(finalAngleRad));
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) finalDir = QVector3D(cos(finalAngleRad), sin(finalAngleRad), 0); gp_Dir finalDir3d = ElCLib::To3d(plane, finalDir2d);
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) finalDir = QVector3D(cos(finalAngleRad), 0, sin(finalAngleRad)); QVector3D finalDir(finalDir3d.X(), finalDir3d.Y(), finalDir3d.Z());
else finalDir = QVector3D(0, cos(finalAngleRad), sin(finalAngleRad));
double lineLength; double lineLength;
if (lengthFromInput) lineLength = inputLength; if (lengthFromInput) lineLength = inputLength;
else { else {
@@ -259,17 +283,17 @@ void LineTool::finalizeCreation()
} }
worldPos = startPos + lineLength * finalDir; worldPos = startPos + lineLength * finalDir;
} else if (lengthFromInput) { } else if (lengthFromInput) {
QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), plane);
QVector3D dir = (currentMouseWorldPos - startPos); QVector3D dir = (currentMouseWorldPos - startPos);
if (dir.length() > 1e-6) { if (dir.length() > 1e-6) {
dir.normalize(); dir.normalize();
worldPos = startPos + inputLength * dir; worldPos = startPos + inputLength * dir;
} else { } else {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos = startPos + QVector3D(inputLength, 0, 0); const auto& xDir = plane.XDirection();
else worldPos = startPos + QVector3D(0, inputLength, 0); worldPos = startPos + inputLength * QVector3D(xDir.X(), xDir.Y(), xDir.Z());
} }
} else { } else {
worldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); worldPos = m_viewport->unproject(m_viewport->currentMousePos(), plane);
} }
gp_Pnt p; gp_Pnt p;
@@ -289,6 +313,10 @@ void LineTool::finalizeCreation()
void LineTool::paintGL() void LineTool::paintGL()
{ {
if (m_isDefining) { if (m_isDefining) {
auto currentPlaneOpt = m_viewport->currentPlane();
if (!currentPlaneOpt) return;
const auto& plane = currentPlaneOpt.value();
QVector<GLfloat> vertices; QVector<GLfloat> vertices;
QVector3D worldPos; QVector3D worldPos;
QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z()); QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
@@ -316,26 +344,24 @@ void LineTool::paintGL()
if (m_viewport->property("isChainedLine").toBool()) { if (m_viewport->property("isChainedLine").toBool()) {
refDir = m_viewport->property("previousLineDirection").value<QVector3D>(); refDir = m_viewport->property("previousLineDirection").value<QVector3D>();
} else { } else {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { const auto& xDir = plane.XDirection();
refDir = QVector3D(1, 0, 0); refDir = QVector3D(xDir.X(), xDir.Y(), xDir.Z());
} else { // YZ
refDir = QVector3D(0, 1, 0);
}
} }
QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), plane);
QVector3D mouseVec = currentMouseWorldPos - startPos; QVector3D mouseVec = currentMouseWorldPos - startPos;
// Quadrant snapping gp_Pnt startPnt(startPos.x(), startPos.y(), startPos.z());
double mouseAngle; gp_Pnt mousePnt(currentMouseWorldPos.x(), currentMouseWorldPos.y(), currentMouseWorldPos.z());
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVec.y(), mouseVec.x())); gp_Dir refDirGp(refDir.x(), refDir.y(), refDir.z());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.x()));
else mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.y()));
double refAngle; gp_Pnt2d startPnt2d(gp_Vec(plane.Location(), startPnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), startPnt).Dot(plane.YDirection()));
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) refAngle = qRadiansToDegrees(atan2(refDir.y(), refDir.x())); gp_Pnt2d mousePnt2d(gp_Vec(plane.Location(), mousePnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), mousePnt).Dot(plane.YDirection()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.x())); gp_Dir2d refDir2d(refDirGp.Dot(plane.XDirection()), refDirGp.Dot(plane.YDirection()));
else refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.y()));
gp_Vec2d mouseVec2d(startPnt2d, mousePnt2d);
double mouseAngle = qRadiansToDegrees(atan2(mouseVec2d.Y(), mouseVec2d.X()));
double refAngle = qRadiansToDegrees(atan2(refDir2d.Y(), refDir2d.X()));
double relativeMouseAngle = mouseAngle - refAngle; double relativeMouseAngle = mouseAngle - refAngle;
while (relativeMouseAngle <= -180.0) relativeMouseAngle += 360.0; while (relativeMouseAngle <= -180.0) relativeMouseAngle += 360.0;
@@ -353,10 +379,9 @@ void LineTool::paintGL()
} }
double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle); double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle);
QVector3D finalDir; gp_Dir2d finalDir2d(cos(finalAngleRad), sin(finalAngleRad));
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) finalDir = QVector3D(cos(finalAngleRad), sin(finalAngleRad), 0); gp_Dir finalDir3d = ElCLib::To3d(plane, finalDir2d);
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) finalDir = QVector3D(cos(finalAngleRad), 0, sin(finalAngleRad)); QVector3D finalDir(finalDir3d.X(), finalDir3d.Y(), finalDir3d.Z());
else finalDir = QVector3D(0, cos(finalAngleRad), sin(finalAngleRad));
double lineLength; double lineLength;
if (lengthFromInput) { if (lengthFromInput) {
@@ -368,33 +393,34 @@ void LineTool::paintGL()
worldPos = startPos + lineLength * finalDir; worldPos = startPos + lineLength * finalDir;
} else if (lengthFromInput) { } else if (lengthFromInput) {
QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), plane);
QVector3D dir = (currentMouseWorldPos - startPos); QVector3D dir = (currentMouseWorldPos - startPos);
if (dir.length() > 1e-6) { if (dir.length() > 1e-6) {
dir.normalize(); dir.normalize();
worldPos = startPos + inputLength * dir; worldPos = startPos + inputLength * dir;
} else { } else {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { const auto& xDir = plane.XDirection();
worldPos = startPos + QVector3D(inputLength, 0, 0); worldPos = startPos + inputLength * QVector3D(xDir.X(), xDir.Y(), xDir.Z());
} else {
worldPos = startPos + QVector3D(0, inputLength, 0);
}
} }
} else { } else {
worldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); worldPos = m_viewport->unproject(m_viewport->currentMousePos(), plane);
gp_Pnt worldPosPnt(worldPos.x(), worldPos.y(), worldPos.z());
if (m_viewport->isSnappingOrigin()) { if (m_viewport->isSnappingOrigin()) {
worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0); worldPosPnt = plane.Location();
} else if (m_viewport->isSnappingVertex()) { } else if (m_viewport->isSnappingVertex()) {
worldPos.setX(m_viewport->snapVertex().X()); worldPos.setY(m_viewport->snapVertex().Y()); worldPos.setZ(m_viewport->snapVertex().Z()); worldPosPnt = m_viewport->snapVertex();
} else if (m_viewport->isSnappingHorizontal()) { } else if (m_viewport->isSnappingHorizontal() || m_viewport->isSnappingVertical()) {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setY(m_firstLinePoint.Y()); gp_Pnt2d worldPos2d(gp_Vec(plane.Location(), worldPosPnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), worldPosPnt).Dot(plane.YDirection()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos.setZ(m_firstLinePoint.Z()); gp_Pnt2d firstPoint2d(gp_Vec(plane.Location(), m_firstLinePoint).Dot(plane.XDirection()), gp_Vec(plane.Location(), m_firstLinePoint).Dot(plane.YDirection()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) worldPos.setZ(m_firstLinePoint.Z()); if (m_viewport->isSnappingHorizontal()) {
} else if (m_viewport->isSnappingVertical()) { worldPos2d.SetY(firstPoint2d.Y());
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setX(m_firstLinePoint.X()); } else { // vertical
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos.setX(m_firstLinePoint.X()); worldPos2d.SetX(firstPoint2d.X());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) worldPos.setY(m_firstLinePoint.Y()); }
worldPosPnt = ElCLib::To3d(plane, worldPos2d);
} }
worldPos.setX(worldPosPnt.X()); worldPos.setY(worldPosPnt.Y()); worldPos.setZ(worldPosPnt.Z());
} }
vertices << m_firstLinePoint.X() << m_firstLinePoint.Y() << m_firstLinePoint.Z(); vertices << m_firstLinePoint.X() << m_firstLinePoint.Y() << m_firstLinePoint.Z();
@@ -416,23 +442,25 @@ void LineTool::paintGL()
if (m_viewport->property("isChainedLine").toBool()) { if (m_viewport->property("isChainedLine").toBool()) {
refDir = m_viewport->property("previousLineDirection").value<QVector3D>(); refDir = m_viewport->property("previousLineDirection").value<QVector3D>();
} else { } else {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refDir = QVector3D(1, 0, 0); const auto& xDir = plane.XDirection();
else refDir = QVector3D(0, 1, 0); refDir = QVector3D(xDir.X(), xDir.Y(), xDir.Z());
} }
if (angleFromInput) { if (angleFromInput) {
QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), plane);
QVector3D mouseVec = currentMouseWorldPos - startPos; QVector3D mouseVec = currentMouseWorldPos - startPos;
double mouseAngle; gp_Pnt startPnt(startPos.x(), startPos.y(), startPos.z());
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVec.y(), mouseVec.x())); gp_Pnt mousePnt(currentMouseWorldPos.x(), currentMouseWorldPos.y(), currentMouseWorldPos.z());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.x())); gp_Dir refDirGp(refDir.x(), refDir.y(), refDir.z());
else mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.y()));
double refAngleForQuadrant; gp_Pnt2d startPnt2d(gp_Vec(plane.Location(), startPnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), startPnt).Dot(plane.YDirection()));
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.y(), refDir.x())); gp_Pnt2d mousePnt2d(gp_Vec(plane.Location(), mousePnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), mousePnt).Dot(plane.YDirection()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.z(), refDir.x())); gp_Dir2d refDir2d(refDirGp.Dot(plane.XDirection()), refDirGp.Dot(plane.YDirection()));
else refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.z(), refDir.y()));
gp_Vec2d mouseVec2d(startPnt2d, mousePnt2d);
double mouseAngle = qRadiansToDegrees(atan2(mouseVec2d.Y(), mouseVec2d.X()));
double refAngleForQuadrant = qRadiansToDegrees(atan2(refDir2d.Y(), refDir2d.X()));
double relativeMouseAngle = mouseAngle - refAngleForQuadrant; double relativeMouseAngle = mouseAngle - refAngleForQuadrant;
while (relativeMouseAngle <= -180.0) relativeMouseAngle += 360.0; while (relativeMouseAngle <= -180.0) relativeMouseAngle += 360.0;
@@ -447,16 +475,14 @@ void LineTool::paintGL()
} }
} }
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { gp_Dir refDirGp(refDir.x(), refDir.y(), refDir.z());
refAngle = atan2(refDir.y(), refDir.x()); gp_Dir lineDirGp(lineVec.x(), lineVec.y(), lineVec.z());
lineAngle = atan2(lineVec.y(), lineVec.x());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { gp_Dir2d refDir2d(refDirGp.Dot(plane.XDirection()), refDirGp.Dot(plane.YDirection()));
refAngle = atan2(refDir.z(), refDir.x()); gp_Dir2d lineDir2d(lineDirGp.Dot(plane.XDirection()), lineDirGp.Dot(plane.YDirection()));
lineAngle = atan2(lineVec.z(), lineVec.x());
} else { // YZ refAngle = atan2(refDir2d.Y(), refDir2d.X());
refAngle = atan2(refDir.z(), refDir.y()); lineAngle = atan2(lineDir2d.Y(), lineDir2d.X());
lineAngle = atan2(lineVec.z(), lineVec.y());
}
angleDiff = lineAngle - refAngle; angleDiff = lineAngle - refAngle;
while (angleDiff <= -M_PI) angleDiff += 2 * M_PI; while (angleDiff <= -M_PI) angleDiff += 2 * M_PI;
@@ -466,14 +492,11 @@ void LineTool::paintGL()
vertices.clear(); vertices.clear();
QVector3D perpVec; gp_Dir lineDirGp(lineVec.x(), lineVec.y(), lineVec.z());
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { gp_Dir2d lineDir2d(lineDirGp.Dot(plane.XDirection()), lineDirGp.Dot(plane.YDirection()));
perpVec = QVector3D(-lineVec.y(), lineVec.x(), 0).normalized(); gp_Dir2d perpDir2d(-lineDir2d.Y(), lineDir2d.X());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { gp_Dir perpDir3d = ElCLib::To3d(plane, perpDir2d);
perpVec = QVector3D(-lineVec.z(), 0, lineVec.x()).normalized(); QVector3D perpVec(perpDir3d.X(), perpDir3d.Y(), perpDir3d.Z());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) {
perpVec = QVector3D(0, -lineVec.z(), lineVec.y()).normalized();
}
if (angleDiff < 0) { if (angleDiff < 0) {
perpVec = -perpVec; perpVec = -perpVec;
@@ -520,9 +543,11 @@ void LineTool::paintGL()
for (int i = 0; i <= numSegments; ++i) { for (int i = 0; i <= numSegments; ++i) {
double angle = refAngle + (lineAngle - refAngle) * i / numSegments; double angle = refAngle + (lineAngle - refAngle) * i / numSegments;
QVector3D p; QVector3D p;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) p = startPos + radius * QVector3D(cos(angle), sin(angle), 0); const auto& xDir = plane.XDirection();
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) p = startPos + radius * QVector3D(cos(angle), 0, sin(angle)); const auto& yDir = plane.YDirection();
else p = startPos + radius * QVector3D(0, cos(angle), sin(angle)); QVector3D u_axis(xDir.X(), xDir.Y(), xDir.Z());
QVector3D v_axis(yDir.X(), yDir.Y(), yDir.Z());
p = startPos + radius * (cos(angle) * u_axis + sin(angle) * v_axis);
vertices << p.x() << p.y() << p.z(); vertices << p.x() << p.y() << p.z();
} }
glLineWidth(1.0f); glLineWidth(1.0f);
@@ -540,17 +565,13 @@ void LineTool::paintGL()
// End arrowhead // End arrowhead
QVector3D endPoint(vertices[vertices.size()-3], vertices[vertices.size()-2], vertices[vertices.size()-1]); QVector3D endPoint(vertices[vertices.size()-3], vertices[vertices.size()-2], vertices[vertices.size()-1]);
double endAngle = lineAngle; double endAngle = lineAngle;
const auto& xDir = plane.XDirection();
const auto& yDir = plane.YDirection();
QVector3D u_axis(xDir.X(), xDir.Y(), xDir.Z());
QVector3D v_axis(yDir.X(), yDir.Y(), yDir.Z());
QVector3D radialDir_end, tangentDir_end; QVector3D radialDir_end, tangentDir_end;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { radialDir_end = cos(endAngle) * u_axis + sin(endAngle) * v_axis;
radialDir_end = QVector3D(cos(endAngle), sin(endAngle), 0); tangentDir_end = -sin(endAngle) * u_axis + cos(endAngle) * v_axis;
tangentDir_end = QVector3D(-sin(endAngle), cos(endAngle), 0);
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
radialDir_end = QVector3D(cos(endAngle), 0, sin(endAngle));
tangentDir_end = QVector3D(-sin(endAngle), 0, cos(endAngle));
} else {
radialDir_end = QVector3D(0, cos(endAngle), sin(endAngle));
tangentDir_end = QVector3D(0, -sin(endAngle), cos(endAngle));
}
QVector3D arc_arrow_base_end = endPoint - sign * arcArrowLength * tangentDir_end; QVector3D arc_arrow_base_end = endPoint - sign * arcArrowLength * tangentDir_end;
QVector3D arc_arrowP1_end = arc_arrow_base_end + arcArrowWidth * radialDir_end; QVector3D arc_arrowP1_end = arc_arrow_base_end + arcArrowWidth * radialDir_end;
QVector3D arc_arrowP2_end = arc_arrow_base_end - arcArrowWidth * radialDir_end; QVector3D arc_arrowP2_end = arc_arrow_base_end - arcArrowWidth * radialDir_end;
@@ -561,16 +582,8 @@ void LineTool::paintGL()
QVector3D startPoint(vertices[0], vertices[1], vertices[2]); QVector3D startPoint(vertices[0], vertices[1], vertices[2]);
double startAngle = refAngle; double startAngle = refAngle;
QVector3D radialDir_start, tangentDir_start; QVector3D radialDir_start, tangentDir_start;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { radialDir_start = cos(startAngle) * u_axis + sin(startAngle) * v_axis;
radialDir_start = QVector3D(cos(startAngle), sin(startAngle), 0); tangentDir_start = -sin(startAngle) * u_axis + cos(startAngle) * v_axis;
tangentDir_start = QVector3D(-sin(startAngle), cos(startAngle), 0);
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
radialDir_start = QVector3D(cos(startAngle), 0, sin(startAngle));
tangentDir_start = QVector3D(-sin(startAngle), 0, cos(startAngle));
} else {
radialDir_start = QVector3D(0, cos(startAngle), sin(startAngle));
tangentDir_start = QVector3D(0, -sin(startAngle), cos(startAngle));
}
QVector3D arc_arrow_base_start = startPoint + sign * arcArrowLength * tangentDir_start; QVector3D arc_arrow_base_start = startPoint + sign * arcArrowLength * tangentDir_start;
QVector3D arc_arrowP1_start = arc_arrow_base_start + arcArrowWidth * radialDir_start; QVector3D arc_arrowP1_start = arc_arrow_base_start + arcArrowWidth * radialDir_start;
QVector3D arc_arrowP2_start = arc_arrow_base_start - arcArrowWidth * radialDir_start; QVector3D arc_arrowP2_start = arc_arrow_base_start - arcArrowWidth * radialDir_start;
@@ -589,29 +602,21 @@ void LineTool::paintGL()
QVector3D midPoint = (startPos + worldPos) / 2.0; QVector3D midPoint = (startPos + worldPos) / 2.0;
const float indicatorSize = 0.02f * -m_viewport->camera()->zoom(); const float indicatorSize = 0.02f * -m_viewport->camera()->zoom();
const float indicatorOffset = 0.02f * -m_viewport->camera()->zoom(); const float indicatorOffset = 0.02f * -m_viewport->camera()->zoom();
const auto& xDir = plane.XDirection();
const auto& yDir = plane.YDirection();
QVector3D u_axis(xDir.X(), xDir.Y(), xDir.Z());
QVector3D v_axis(yDir.X(), yDir.Y(), yDir.Z());
QVector3D p1, p2;
if (m_viewport->isSnappingHorizontal()) { if (m_viewport->isSnappingHorizontal()) {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { p1 = midPoint - indicatorSize * v_axis + indicatorOffset * u_axis;
vertices << midPoint.x() - indicatorSize << midPoint.y() + indicatorOffset << midPoint.z(); p2 = midPoint + indicatorSize * v_axis + indicatorOffset * u_axis;
vertices << midPoint.x() + indicatorSize << midPoint.y() + indicatorOffset << midPoint.z();
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
vertices << midPoint.x() - indicatorSize << midPoint.y() << midPoint.z() + indicatorOffset;
vertices << midPoint.x() + indicatorSize << midPoint.y() << midPoint.z() + indicatorOffset;
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) {
vertices << midPoint.x() << midPoint.y() - indicatorSize << midPoint.z() + indicatorOffset;
vertices << midPoint.x() << midPoint.y() + indicatorSize << midPoint.z() + indicatorOffset;
}
} else { // m_isSnappingVertical } else { // m_isSnappingVertical
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { p1 = midPoint - indicatorSize * u_axis + indicatorOffset * v_axis;
vertices << midPoint.x() + indicatorOffset << midPoint.y() - indicatorSize << midPoint.z(); p2 = midPoint + indicatorSize * u_axis + indicatorOffset * v_axis;
vertices << midPoint.x() + indicatorOffset << midPoint.y() + indicatorSize << midPoint.z();
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
vertices << midPoint.x() + indicatorOffset << midPoint.y() << midPoint.z() - indicatorSize;
vertices << midPoint.x() + indicatorOffset << midPoint.y() << midPoint.z() + indicatorSize;
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) {
vertices << midPoint.x() << midPoint.y() + indicatorOffset << midPoint.z() - indicatorSize;
vertices << midPoint.x() << midPoint.y() + indicatorOffset << midPoint.z() + indicatorSize;
}
} }
vertices << p1.x() << p1.y() << p1.z();
vertices << p2.x() << p2.y() << p2.z();
m_viewport->vbo().bind(); m_viewport->vbo().bind();
m_viewport->vbo().allocate(vertices.constData(), vertices.size() * sizeof(GLfloat)); m_viewport->vbo().allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
glDrawArrays(GL_LINES, 0, 2); glDrawArrays(GL_LINES, 0, 2);
@@ -622,6 +627,10 @@ void LineTool::paintGL()
void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection) void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection)
{ {
if (m_isDefining) { if (m_isDefining) {
auto currentPlaneOpt = m_viewport->currentPlane();
if (!currentPlaneOpt) return;
const auto& plane = currentPlaneOpt.value();
QVector3D worldPos; QVector3D worldPos;
QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z()); QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
QString dimText; QString dimText;
@@ -651,25 +660,24 @@ void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMa
if (m_viewport->property("isChainedLine").toBool()) { if (m_viewport->property("isChainedLine").toBool()) {
refDir = m_viewport->property("previousLineDirection").value<QVector3D>(); refDir = m_viewport->property("previousLineDirection").value<QVector3D>();
} else { } else {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { const auto& xDir = plane.XDirection();
refDir = QVector3D(1, 0, 0); refDir = QVector3D(xDir.X(), xDir.Y(), xDir.Z());
} else { // YZ
refDir = QVector3D(0, 1, 0);
}
} }
QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), plane);
QVector3D mouseVec = currentMouseWorldPos - startPos; QVector3D mouseVec = currentMouseWorldPos - startPos;
double mouseAngle; gp_Pnt startPnt(startPos.x(), startPos.y(), startPos.z());
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVec.y(), mouseVec.x())); gp_Pnt mousePnt(currentMouseWorldPos.x(), currentMouseWorldPos.y(), currentMouseWorldPos.z());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.x())); gp_Dir refDirGp(refDir.x(), refDir.y(), refDir.z());
else mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.y()));
double refAngle; gp_Pnt2d startPnt2d(gp_Vec(plane.Location(), startPnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), startPnt).Dot(plane.YDirection()));
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) refAngle = qRadiansToDegrees(atan2(refDir.y(), refDir.x())); gp_Pnt2d mousePnt2d(gp_Vec(plane.Location(), mousePnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), mousePnt).Dot(plane.YDirection()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.x())); gp_Dir2d refDir2d(refDirGp.Dot(plane.XDirection()), refDirGp.Dot(plane.YDirection()));
else refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.y()));
gp_Vec2d mouseVec2d(startPnt2d, mousePnt2d);
double mouseAngle = qRadiansToDegrees(atan2(mouseVec2d.Y(), mouseVec2d.X()));
double refAngle = qRadiansToDegrees(atan2(refDir2d.Y(), refDir2d.X()));
double relativeMouseAngle = mouseAngle - refAngle; double relativeMouseAngle = mouseAngle - refAngle;
while (relativeMouseAngle <= -180.0) relativeMouseAngle += 360.0; while (relativeMouseAngle <= -180.0) relativeMouseAngle += 360.0;
@@ -687,10 +695,9 @@ void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMa
} }
double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle); double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle);
QVector3D finalDir; gp_Dir2d finalDir2d(cos(finalAngleRad), sin(finalAngleRad));
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) finalDir = QVector3D(cos(finalAngleRad), sin(finalAngleRad), 0); gp_Dir finalDir3d = ElCLib::To3d(plane, finalDir2d);
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) finalDir = QVector3D(cos(finalAngleRad), 0, sin(finalAngleRad)); QVector3D finalDir(finalDir3d.X(), finalDir3d.Y(), finalDir3d.Z());
else finalDir = QVector3D(0, cos(finalAngleRad), sin(finalAngleRad));
if (lengthFromInput) { if (lengthFromInput) {
lineLength = inputLength; lineLength = inputLength;
@@ -702,33 +709,34 @@ void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMa
} else if (lengthFromInput) { } else if (lengthFromInput) {
lineLength = inputLength; lineLength = inputLength;
QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), plane);
QVector3D dir = (currentMouseWorldPos - startPos); QVector3D dir = (currentMouseWorldPos - startPos);
if (dir.length() > 1e-6) { if (dir.length() > 1e-6) {
dir.normalize(); dir.normalize();
worldPos = startPos + inputLength * dir; worldPos = startPos + inputLength * dir;
} else { } else {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { const auto& xDir = plane.XDirection();
worldPos = startPos + QVector3D(inputLength, 0, 0); worldPos = startPos + inputLength * QVector3D(xDir.X(), xDir.Y(), xDir.Z());
} else {
worldPos = startPos + QVector3D(0, inputLength, 0);
}
} }
} else { } else {
worldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); worldPos = m_viewport->unproject(m_viewport->currentMousePos(), plane);
gp_Pnt worldPosPnt(worldPos.x(), worldPos.y(), worldPos.z());
if (m_viewport->isSnappingOrigin()) { if (m_viewport->isSnappingOrigin()) {
worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0); worldPosPnt = plane.Location();
} else if (m_viewport->isSnappingVertex()) { } else if (m_viewport->isSnappingVertex()) {
worldPos.setX(m_viewport->snapVertex().X()); worldPos.setY(m_viewport->snapVertex().Y()); worldPos.setZ(m_viewport->snapVertex().Z()); worldPosPnt = m_viewport->snapVertex();
} else if (m_viewport->isSnappingHorizontal()) { } else if (m_viewport->isSnappingHorizontal() || m_viewport->isSnappingVertical()) {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setY(m_firstLinePoint.Y()); gp_Pnt2d worldPos2d(gp_Vec(plane.Location(), worldPosPnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), worldPosPnt).Dot(plane.YDirection()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos.setZ(m_firstLinePoint.Z()); gp_Pnt2d firstPoint2d(gp_Vec(plane.Location(), m_firstLinePoint).Dot(plane.XDirection()), gp_Vec(plane.Location(), m_firstLinePoint).Dot(plane.YDirection()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) worldPos.setZ(m_firstLinePoint.Z()); if (m_viewport->isSnappingHorizontal()) {
} else if (m_viewport->isSnappingVertical()) { worldPos2d.SetY(firstPoint2d.Y());
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setX(m_firstLinePoint.X()); } else { // vertical
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos.setX(m_firstLinePoint.X()); worldPos2d.SetX(firstPoint2d.X());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) worldPos.setY(m_firstLinePoint.Y()); }
worldPosPnt = ElCLib::To3d(plane, worldPos2d);
} }
worldPos.setX(worldPosPnt.X()); worldPos.setY(worldPosPnt.Y()); worldPos.setZ(worldPosPnt.Z());
lineLength = (worldPos - startPos).length(); lineLength = (worldPos - startPos).length();
} }
@@ -739,24 +747,26 @@ void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMa
if (m_viewport->property("isChainedLine").toBool()) { if (m_viewport->property("isChainedLine").toBool()) {
refDir = m_viewport->property("previousLineDirection").value<QVector3D>(); refDir = m_viewport->property("previousLineDirection").value<QVector3D>();
} else { } else {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refDir = QVector3D(1, 0, 0); const auto& xDir = plane.XDirection();
else refDir = QVector3D(0, 1, 0); refDir = QVector3D(xDir.X(), xDir.Y(), xDir.Z());
} }
QVector3D currentMouseWorldPosForText = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); QVector3D currentMouseWorldPosForText = m_viewport->unproject(m_viewport->currentMousePos(), plane);
QVector3D mouseVecForText = currentMouseWorldPosForText - startPos; QVector3D mouseVecForText = currentMouseWorldPosForText - startPos;
if (angleFromInput) { if (angleFromInput) {
if (mouseVecForText.length() > 1e-6) { if (mouseVecForText.length() > 1e-6) {
double mouseAngle; gp_Pnt startPnt(startPos.x(), startPos.y(), startPos.z());
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVecForText.y(), mouseVecForText.x())); gp_Pnt mousePnt(currentMouseWorldPosForText.x(), currentMouseWorldPosForText.y(), currentMouseWorldPosForText.z());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVecForText.z(), mouseVecForText.x())); gp_Dir refDirGp(refDir.x(), refDir.y(), refDir.z());
else mouseAngle = qRadiansToDegrees(atan2(mouseVecForText.z(), mouseVecForText.y()));
double refAngleForQuadrant; gp_Pnt2d startPnt2d(gp_Vec(plane.Location(), startPnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), startPnt).Dot(plane.YDirection()));
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.y(), refDir.x())); gp_Pnt2d mousePnt2d(gp_Vec(plane.Location(), mousePnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), mousePnt).Dot(plane.YDirection()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.z(), refDir.x())); gp_Dir2d refDir2d(refDirGp.Dot(plane.XDirection()), refDirGp.Dot(plane.YDirection()));
else refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.z(), refDir.y()));
gp_Vec2d mouseVec2d(startPnt2d, mousePnt2d);
double mouseAngle = qRadiansToDegrees(atan2(mouseVec2d.Y(), mouseVec2d.X()));
double refAngleForQuadrant = qRadiansToDegrees(atan2(refDir2d.Y(), refDir2d.X()));
double relativeMouseAngle = mouseAngle - refAngleForQuadrant; double relativeMouseAngle = mouseAngle - refAngleForQuadrant;
while (relativeMouseAngle <= -180.0) relativeMouseAngle += 360.0; while (relativeMouseAngle <= -180.0) relativeMouseAngle += 360.0;
@@ -772,30 +782,23 @@ void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMa
} }
} }
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { gp_Dir refDirGp(refDir.x(), refDir.y(), refDir.z());
refAngle = atan2(refDir.y(), refDir.x()); gp_Dir lineDirGp(lineVec.x(), lineVec.y(), lineVec.z());
lineAngle = atan2(lineVec.y(), lineVec.x());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { gp_Dir2d refDir2d(refDirGp.Dot(plane.XDirection()), refDirGp.Dot(plane.YDirection()));
refAngle = atan2(refDir.z(), refDir.x()); gp_Dir2d lineDir2d(lineDirGp.Dot(plane.XDirection()), lineDirGp.Dot(plane.YDirection()));
lineAngle = atan2(lineVec.z(), lineVec.x());
} else { // YZ refAngle = atan2(refDir2d.Y(), refDir2d.X());
refAngle = atan2(refDir.z(), refDir.y()); lineAngle = atan2(lineDir2d.Y(), lineDir2d.X());
lineAngle = atan2(lineVec.z(), lineVec.y());
}
double angleDiff = lineAngle - refAngle; double angleDiff = lineAngle - refAngle;
while (angleDiff <= -M_PI) angleDiff += 2 * M_PI; while (angleDiff <= -M_PI) angleDiff += 2 * M_PI;
while (angleDiff > M_PI) angleDiff -= 2 * M_PI; while (angleDiff > M_PI) angleDiff -= 2 * M_PI;
lineAngle = refAngle + angleDiff; lineAngle = refAngle + angleDiff;
QVector3D perpVec; gp_Dir2d perpDir2d(-lineDir2d.Y(), lineDir2d.X());
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { gp_Dir perpDir3d = ElCLib::To3d(plane, perpDir2d);
perpVec = QVector3D(-lineVec.y(), lineVec.x(), 0).normalized(); QVector3D perpVec(perpDir3d.X(), perpDir3d.Y(), perpDir3d.Z());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
perpVec = QVector3D(-lineVec.z(), 0, lineVec.x()).normalized();
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) {
perpVec = QVector3D(0, -lineVec.z(), lineVec.y()).normalized();
}
if (angleDiff < 0) { if (angleDiff < 0) {
perpVec = -perpVec; perpVec = -perpVec;
@@ -838,9 +841,11 @@ void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMa
QVector3D textPos3DAngle; QVector3D textPos3DAngle;
float textOffset = 0.035f * -m_viewport->camera()->zoom(); float textOffset = 0.035f * -m_viewport->camera()->zoom();
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) textPos3DAngle = startPos + (radius + textOffset) * QVector3D(cos(midAngle), sin(midAngle), 0); const auto& xDir = plane.XDirection();
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) textPos3DAngle = startPos + (radius + textOffset) * QVector3D(cos(midAngle), 0, sin(midAngle)); const auto& yDir = plane.YDirection();
else textPos3DAngle = startPos + (radius + textOffset) * QVector3D(0, cos(midAngle), sin(midAngle)); QVector3D u_axis(xDir.X(), xDir.Y(), xDir.Z());
QVector3D v_axis(yDir.X(), yDir.Y(), yDir.Z());
textPos3DAngle = startPos + (radius + textOffset) * (cos(midAngle) * u_axis + sin(midAngle) * v_axis);
QVector3D screenPosAngle = m_viewport->project(textPos3DAngle, modelView, projection, m_viewport->rect()); QVector3D screenPosAngle = m_viewport->project(textPos3DAngle, modelView, projection, m_viewport->rect());
if (screenPosAngle.z() < 1.0f) { if (screenPosAngle.z() < 1.0f) {
+224 -260
View File
@@ -15,6 +15,11 @@
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <cmath> #include <cmath>
#include <QtMath> #include <QtMath>
#include <optional>
#include <gp_Ax2.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Vec.hxx>
#include <ElCLib.hxx>
RectangleTool::RectangleTool(ViewportWidget* viewport) RectangleTool::RectangleTool(ViewportWidget* viewport)
: SketchTool(viewport) : SketchTool(viewport)
@@ -35,14 +40,18 @@ void RectangleTool::activate()
void RectangleTool::mousePressEvent(QMouseEvent *event) void RectangleTool::mousePressEvent(QMouseEvent *event)
{ {
auto currentPlaneOpt = m_viewport->currentPlane();
if (!currentPlaneOpt) return;
const auto& plane = currentPlaneOpt.value();
gp_Pnt p; gp_Pnt p;
if (!m_isDefining) { if (!m_isDefining) {
if (m_viewport->isSnappingOrigin()) { if (m_viewport->isSnappingOrigin()) {
p.SetCoord(0, 0, 0); p = plane.Location();
} else if (m_viewport->isSnappingVertex()) { } else if (m_viewport->isSnappingVertex()) {
p = m_viewport->snapVertex(); p = m_viewport->snapVertex();
} else { } else {
QVector3D worldPos = m_viewport->unproject(event->pos(), m_viewport->currentPlane()); QVector3D worldPos = m_viewport->unproject(event->pos(), plane);
p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z()); p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z());
} }
m_firstRectanglePoint = p; m_firstRectanglePoint = p;
@@ -51,8 +60,8 @@ void RectangleTool::mousePressEvent(QMouseEvent *event)
m_viewport->setProperty("heightInput", ""); m_viewport->setProperty("heightInput", "");
m_viewport->setProperty("dimensionEditMode", "height"); m_viewport->setProperty("dimensionEditMode", "height");
} else { } else {
QVector3D worldPos; QVector3D worldPosQ;
QVector3D startPos(m_firstRectanglePoint.X(), m_firstRectanglePoint.Y(), m_firstRectanglePoint.Z()); gp_Pnt startPos = m_firstRectanglePoint;
QString widthInput = m_viewport->property("widthInput").toString(); QString widthInput = m_viewport->property("widthInput").toString();
QString heightInput = m_viewport->property("heightInput").toString(); QString heightInput = m_viewport->property("heightInput").toString();
@@ -71,45 +80,35 @@ void RectangleTool::mousePressEvent(QMouseEvent *event)
} }
if (widthFromInput || heightFromInput) { if (widthFromInput || heightFromInput) {
QVector3D mousePos = m_viewport->unproject(event->pos(), m_viewport->currentPlane()); QVector3D mousePosQ = m_viewport->unproject(event->pos(), plane);
QVector3D mouseDir = mousePos - startPos; gp_Pnt mousePos(mousePosQ.x(), mousePosQ.y(), mousePosQ.z());
double current_w, current_h;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { gp_Pnt2d startPos2d(gp_Vec(plane.Location(), startPos).Dot(plane.XDirection()), gp_Vec(plane.Location(), startPos).Dot(plane.YDirection()));
current_w = qAbs(mouseDir.x()); gp_Pnt2d mousePos2d(gp_Vec(plane.Location(), mousePos).Dot(plane.XDirection()), gp_Vec(plane.Location(), mousePos).Dot(plane.YDirection()));
current_h = qAbs(mouseDir.y());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { double current_w = qAbs(mousePos2d.X() - startPos2d.X());
current_w = qAbs(mouseDir.x()); double current_h = qAbs(mousePos2d.Y() - startPos2d.Y());
current_h = qAbs(mouseDir.z());
} else { // YZ
current_w = qAbs(mouseDir.y());
current_h = qAbs(mouseDir.z());
}
double rect_w = widthFromInput ? inputWidth : current_w; double rect_w = widthFromInput ? inputWidth : current_w;
double rect_h = heightFromInput ? inputHeight : current_h; double rect_h = heightFromInput ? inputHeight : current_h;
int signX = (mouseDir.x() >= 0) ? 1 : -1;
int signY = (mouseDir.y() >= 0) ? 1 : -1; int signX = (mousePos2d.X() >= startPos2d.X()) ? 1 : -1;
int signZ = (mouseDir.z() >= 0) ? 1 : -1; int signY = (mousePos2d.Y() >= startPos2d.Y()) ? 1 : -1;
worldPos = startPos;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { gp_Pnt2d endPos2d(startPos2d.X() + signX * rect_w, startPos2d.Y() + signY * rect_h);
worldPos.setX(startPos.x() + signX * rect_w); gp_Pnt endPos3d = ElCLib::To3d(plane, endPos2d);
worldPos.setY(startPos.y() + signY * rect_h); worldPosQ = QVector3D(endPos3d.X(), endPos3d.Y(), endPos3d.Z());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
worldPos.setX(startPos.x() + signX * rect_w);
worldPos.setZ(startPos.z() + signZ * rect_h);
} else { // YZ
worldPos.setY(startPos.y() + signY * rect_w);
worldPos.setZ(startPos.z() + signZ * rect_h);
}
} else { } else {
if (m_viewport->isSnappingOrigin()) { if (m_viewport->isSnappingOrigin()) {
worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0); const auto& origin = plane.Location();
worldPosQ.setX(origin.X()); worldPosQ.setY(origin.Y()); worldPosQ.setZ(origin.Z());
} else if (m_viewport->isSnappingVertex()) { } else if (m_viewport->isSnappingVertex()) {
worldPos = QVector3D(m_viewport->snapVertex().X(), m_viewport->snapVertex().Y(), m_viewport->snapVertex().Z()); worldPosQ = QVector3D(m_viewport->snapVertex().X(), m_viewport->snapVertex().Y(), m_viewport->snapVertex().Z());
} else { } else {
worldPos = m_viewport->unproject(event->pos(), m_viewport->currentPlane()); worldPosQ = m_viewport->unproject(event->pos(), plane);
} }
} }
p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z()); p.SetCoord(worldPosQ.x(), worldPosQ.y(), worldPosQ.z());
emit m_viewport->rectangleAdded(m_firstRectanglePoint, p); emit m_viewport->rectangleAdded(m_firstRectanglePoint, p);
deactivate(); deactivate();
} }
@@ -122,8 +121,12 @@ void RectangleTool::mouseMoveEvent(QMouseEvent *event)
void RectangleTool::finalizeCreation() void RectangleTool::finalizeCreation()
{ {
QVector3D worldPos; auto currentPlaneOpt = m_viewport->currentPlane();
QVector3D startPos(m_firstRectanglePoint.X(), m_firstRectanglePoint.Y(), m_firstRectanglePoint.Z()); if (!currentPlaneOpt) return;
const auto& plane = currentPlaneOpt.value();
QVector3D worldPosQ;
gp_Pnt startPos = m_firstRectanglePoint;
QString widthInput = m_viewport->property("widthInput").toString(); QString widthInput = m_viewport->property("widthInput").toString();
QString heightInput = m_viewport->property("heightInput").toString(); QString heightInput = m_viewport->property("heightInput").toString();
@@ -142,41 +145,30 @@ void RectangleTool::finalizeCreation()
} }
if (widthFromInput || heightFromInput) { if (widthFromInput || heightFromInput) {
QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); QVector3D mousePosQ = m_viewport->unproject(m_viewport->currentMousePos(), plane);
QVector3D mouseDir = mousePos - startPos; gp_Pnt mousePos(mousePosQ.x(), mousePosQ.y(), mousePosQ.z());
double current_w, current_h;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { gp_Pnt2d startPos2d(gp_Vec(plane.Location(), startPos).Dot(plane.XDirection()), gp_Vec(plane.Location(), startPos).Dot(plane.YDirection()));
current_w = qAbs(mouseDir.x()); gp_Pnt2d mousePos2d(gp_Vec(plane.Location(), mousePos).Dot(plane.XDirection()), gp_Vec(plane.Location(), mousePos).Dot(plane.YDirection()));
current_h = qAbs(mouseDir.y());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { double current_w = qAbs(mousePos2d.X() - startPos2d.X());
current_w = qAbs(mouseDir.x()); double current_h = qAbs(mousePos2d.Y() - startPos2d.Y());
current_h = qAbs(mouseDir.z());
} else { // YZ
current_w = qAbs(mouseDir.y());
current_h = qAbs(mouseDir.z());
}
double rect_w = widthFromInput ? inputWidth : current_w; double rect_w = widthFromInput ? inputWidth : current_w;
double rect_h = heightFromInput ? inputHeight : current_h; double rect_h = heightFromInput ? inputHeight : current_h;
int signX = (mouseDir.x() >= 0) ? 1 : -1;
int signY = (mouseDir.y() >= 0) ? 1 : -1; int signX = (mousePos2d.X() >= startPos2d.X()) ? 1 : -1;
int signZ = (mouseDir.z() >= 0) ? 1 : -1; int signY = (mousePos2d.Y() >= startPos2d.Y()) ? 1 : -1;
worldPos = startPos;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { gp_Pnt2d endPos2d(startPos2d.X() + signX * rect_w, startPos2d.Y() + signY * rect_h);
worldPos.setX(startPos.x() + signX * rect_w); gp_Pnt endPos3d = ElCLib::To3d(plane, endPos2d);
worldPos.setY(startPos.y() + signY * rect_h); worldPosQ = QVector3D(endPos3d.X(), endPos3d.Y(), endPos3d.Z());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
worldPos.setX(startPos.x() + signX * rect_w);
worldPos.setZ(startPos.z() + signZ * rect_h);
} else { // YZ
worldPos.setY(startPos.y() + signY * rect_w);
worldPos.setZ(startPos.z() + signZ * rect_h);
}
} else { } else {
worldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); worldPosQ = m_viewport->unproject(m_viewport->currentMousePos(), plane);
} }
gp_Pnt p; gp_Pnt p;
p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z()); p.SetCoord(worldPosQ.x(), worldPosQ.y(), worldPosQ.z());
emit m_viewport->rectangleAdded(m_firstRectanglePoint, p); emit m_viewport->rectangleAdded(m_firstRectanglePoint, p);
deactivate(); deactivate();
@@ -184,216 +176,188 @@ void RectangleTool::finalizeCreation()
void RectangleTool::paintGL() void RectangleTool::paintGL()
{ {
if (m_isDefining) { if (!m_isDefining) return;
QVector<GLfloat> vertices; auto currentPlaneOpt = m_viewport->currentPlane();
QVector3D worldPos; if (!currentPlaneOpt) return;
QVector3D startPos(m_firstRectanglePoint.X(), m_firstRectanglePoint.Y(), m_firstRectanglePoint.Z()); const auto& plane = currentPlaneOpt.value();
QString widthInput = m_viewport->property("widthInput").toString(); QVector<GLfloat> vertices;
QString heightInput = m_viewport->property("heightInput").toString(); QVector3D worldPosQ;
bool widthFromInput = false; gp_Pnt startPos = m_firstRectanglePoint;
bool heightFromInput = false;
double inputWidth = 0, inputHeight = 0;
if (!widthInput.isEmpty()) { QString widthInput = m_viewport->property("widthInput").toString();
bool ok; QString heightInput = m_viewport->property("heightInput").toString();
inputWidth = widthInput.toDouble(&ok); bool widthFromInput = false;
if (ok) widthFromInput = true; bool heightFromInput = false;
} double inputWidth = 0, inputHeight = 0;
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 (!widthInput.isEmpty()) {
bool ok;
if (widthFromInput || heightFromInput) { inputWidth = widthInput.toDouble(&ok);
QVector3D mouseDir = mousePos - startPos; if (ok) widthFromInput = true;
double current_w, current_h;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
current_w = qAbs(mouseDir.x());
current_h = qAbs(mouseDir.y());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
current_w = qAbs(mouseDir.x());
current_h = qAbs(mouseDir.z());
} 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.setY(startPos.y() + signY * rect_h);
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
worldPos.setX(startPos.x() + signX * rect_w);
worldPos.setZ(startPos.z() + signZ * 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(p3.y()); p4.setZ(p1.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(p1.y()); p4.setZ(p3.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);
} }
if (!heightInput.isEmpty()) {
bool ok;
inputHeight = heightInput.toDouble(&ok);
if (ok) heightFromInput = true;
}
QVector3D mousePosQ = m_viewport->unproject(m_viewport->currentMousePos(), plane);
gp_Pnt mousePos(mousePosQ.x(), mousePosQ.y(), mousePosQ.z());
if (widthFromInput || heightFromInput) {
gp_Pnt2d startPos2d(gp_Vec(plane.Location(), startPos).Dot(plane.XDirection()), gp_Vec(plane.Location(), startPos).Dot(plane.YDirection()));
gp_Pnt2d mousePos2d(gp_Vec(plane.Location(), mousePos).Dot(plane.XDirection()), gp_Vec(plane.Location(), mousePos).Dot(plane.YDirection()));
double current_w = qAbs(mousePos2d.X() - startPos2d.X());
double current_h = qAbs(mousePos2d.Y() - startPos2d.Y());
double rect_w = widthFromInput ? inputWidth : current_w;
double rect_h = heightFromInput ? inputHeight : current_h;
int signX = (mousePos2d.X() >= startPos2d.X()) ? 1 : -1;
int signY = (mousePos2d.Y() >= startPos2d.Y()) ? 1 : -1;
gp_Pnt2d endPos2d(startPos2d.X() + signX * rect_w, startPos2d.Y() + signY * rect_h);
gp_Pnt endPos3d = ElCLib::To3d(plane, endPos2d);
worldPosQ = QVector3D(endPos3d.X(), endPos3d.Y(), endPos3d.Z());
} else {
worldPosQ = mousePosQ;
if (m_viewport->isSnappingOrigin()) {
const auto& origin = plane.Location();
worldPosQ.setX(origin.X()); worldPosQ.setY(origin.Y()); worldPosQ.setZ(origin.Z());
} else if (m_viewport->isSnappingVertex()) {
worldPosQ.setX(m_viewport->snapVertex().X()); worldPosQ.setY(m_viewport->snapVertex().Y()); worldPosQ.setZ(m_viewport->snapVertex().Z());
}
}
gp_Pnt p1_3d = startPos;
gp_Pnt p3_3d(worldPosQ.x(), worldPosQ.y(), worldPosQ.z());
gp_Pnt2d p1_2d(gp_Vec(plane.Location(), p1_3d).Dot(plane.XDirection()), gp_Vec(plane.Location(), p1_3d).Dot(plane.YDirection()));
gp_Pnt2d p3_2d(gp_Vec(plane.Location(), p3_3d).Dot(plane.XDirection()), gp_Vec(plane.Location(), p3_3d).Dot(plane.YDirection()));
gp_Pnt2d p2_2d(p3_2d.X(), p1_2d.Y());
gp_Pnt2d p4_2d(p1_2d.X(), p3_2d.Y());
gp_Pnt p2_3d = ElCLib::To3d(plane, p2_2d);
gp_Pnt p4_3d = ElCLib::To3d(plane, p4_2d);
vertices << p1_3d.X() << p1_3d.Y() << p1_3d.Z();
vertices << p2_3d.X() << p2_3d.Y() << p2_3d.Z();
vertices << p2_3d.X() << p2_3d.Y() << p2_3d.Z();
vertices << p3_3d.X() << p3_3d.Y() << p3_3d.Z();
vertices << p3_3d.X() << p3_3d.Y() << p3_3d.Z();
vertices << p4_3d.X() << p4_3d.Y() << p4_3d.Z();
vertices << p4_3d.X() << p4_3d.Y() << p4_3d.Z();
vertices << p1_3d.X() << p1_3d.Y() << p1_3d.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) void RectangleTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection)
{ {
if (m_isDefining) { if (!m_isDefining) return;
QVector3D worldPos; auto currentPlaneOpt = m_viewport->currentPlane();
QVector3D p1_3d(m_firstRectanglePoint.X(), m_firstRectanglePoint.Y(), m_firstRectanglePoint.Z()); if (!currentPlaneOpt) return;
const auto& plane = currentPlaneOpt.value();
QString widthInput = m_viewport->property("widthInput").toString(); QVector3D worldPosQ;
QString heightInput = m_viewport->property("heightInput").toString(); gp_Pnt p1_3d = m_firstRectanglePoint;
bool widthFromInput = false;
bool heightFromInput = false;
double inputWidth = 0, inputHeight = 0;
if (!widthInput.isEmpty()) { QString widthInput = m_viewport->property("widthInput").toString();
bool ok; QString heightInput = m_viewport->property("heightInput").toString();
inputWidth = widthInput.toDouble(&ok); bool widthFromInput = false;
if (ok) widthFromInput = true; bool heightFromInput = false;
} double inputWidth = 0, inputHeight = 0;
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 (!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 mousePosQ = m_viewport->unproject(m_viewport->currentMousePos(), plane);
QVector3D mouseDir = mousePos - p1_3d; gp_Pnt mousePos(mousePosQ.x(), mousePosQ.y(), mousePosQ.z());
double current_w, current_h;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
current_w = qAbs(mouseDir.x());
current_h = qAbs(mouseDir.y());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
current_w = qAbs(mouseDir.x());
current_h = qAbs(mouseDir.z());
} 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.setY(p1_3d.y() + signY * rect_h);
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
worldPos.setX(p1_3d.x() + signX * rect_w);
worldPos.setZ(p1_3d.z() + signZ * 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 (widthFromInput || heightFromInput) {
gp_Pnt2d startPos2d(gp_Vec(plane.Location(), p1_3d).Dot(plane.XDirection()), gp_Vec(plane.Location(), p1_3d).Dot(plane.YDirection()));
gp_Pnt2d mousePos2d(gp_Vec(plane.Location(), mousePos).Dot(plane.XDirection()), gp_Vec(plane.Location(), mousePos).Dot(plane.YDirection()));
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { double current_w = qAbs(mousePos2d.X() - startPos2d.X());
p2_3d.setX(p3_3d.x()); p2_3d.setY(p1_3d.y()); p2_3d.setZ(p1_3d.z()); double current_h = qAbs(mousePos2d.Y() - startPos2d.Y());
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 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(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 { // 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); double rect_w = widthFromInput ? inputWidth : current_w;
QFontMetrics fm(painter.font()); double rect_h = heightFromInput ? inputHeight : current_h;
int signX = (mousePos2d.X() >= startPos2d.X()) ? 1 : -1;
int signY = (mousePos2d.Y() >= startPos2d.Y()) ? 1 : -1;
// Width dimension gp_Pnt2d endPos2d(startPos2d.X() + signX * rect_w, startPos2d.Y() + signY * rect_h);
QVector3D widthTextPos3D = (p1_3d + p2_3d) / 2.0f; gp_Pnt endPos3d = ElCLib::To3d(plane, endPos2d);
QVector3D screenPosW = m_viewport->project(widthTextPos3D, modelView, projection, m_viewport->rect()); worldPosQ = QVector3D(endPos3d.X(), endPos3d.Y(), endPos3d.Z());
if (screenPosW.z() < 1.0f) { } else {
QString widthText = widthFromInput ? widthInput : QString::number(w, 'f', 2); worldPosQ = mousePosQ;
QRect textRect = fm.boundingRect(widthText + "__"); if (m_viewport->isSnappingOrigin()) {
textRect.moveCenter(screenPosW.toPoint() + QPoint(0, (p3_3d.z() > p1_3d.z() || p3_3d.y() > p1_3d.y()) ? -15 : 15)); const auto& origin = plane.Location();
if (m_viewport->property("dimensionEditMode").toString() == "width") { worldPosQ.setX(origin.X()); worldPosQ.setY(origin.Y()); worldPosQ.setZ(origin.Z());
painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(64, 128, 255)); } else if (m_viewport->isSnappingVertex()) {
} else { worldPosQ.setX(m_viewport->snapVertex().X()); worldPosQ.setY(m_viewport->snapVertex().Y()); worldPosQ.setZ(m_viewport->snapVertex().Z());
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);
} }
} }
gp_Pnt p3_3d(worldPosQ.x(), worldPosQ.y(), worldPosQ.z());
gp_Pnt p2_3d, p4_3d;
gp_Pnt2d p1_2d(gp_Vec(plane.Location(), p1_3d).Dot(plane.XDirection()), gp_Vec(plane.Location(), p1_3d).Dot(plane.YDirection()));
gp_Pnt2d p3_2d(gp_Vec(plane.Location(), p3_3d).Dot(plane.XDirection()), gp_Vec(plane.Location(), p3_3d).Dot(plane.YDirection()));
gp_Pnt2d p2_2d(p3_2d.X(), p1_2d.Y());
p2_3d = ElCLib::To3d(plane, p2_2d);
double w = qAbs(p3_2d.X() - p1_2d.X());
double h = qAbs(p3_2d.Y() - p1_2d.Y());
painter.setRenderHint(QPainter::Antialiasing);
QFontMetrics fm(painter.font());
QVector3D p1_q(p1_3d.X(), p1_3d.Y(), p1_3d.Z());
QVector3D p2_q(p2_3d.X(), p2_3d.Y(), p2_3d.Z());
QVector3D p3_q(p3_3d.X(), p3_3d.Y(), p3_3d.Z());
// Width dimension
QVector3D widthTextPos3D = (p1_q + p2_q) / 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_2d.Y() > p1_2d.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_q + p3_q) / 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_2d.X() > p1_2d.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);
}
} }
+66 -15
View File
@@ -10,11 +10,44 @@
#include "SketchLine.h" #include "SketchLine.h"
#include "SketchRectangle.h" #include "SketchRectangle.h"
#include <BRep_Builder.hxx>
#include <TopoDS_Compound.hxx>
#include <gp_Pnt.hxx>
#include <gp_Dir.hxx>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonObject>
namespace
{
void gpPntToJson(const gp_Pnt& p, QJsonObject& json) {
json["x"] = p.X();
json["y"] = p.Y();
json["z"] = p.Z();
}
gp_Pnt jsonToGpPnt(const QJsonObject& json) {
return gp_Pnt(json["x"].toDouble(), json["y"].toDouble(), json["z"].toDouble());
}
void gpDirToJson(const gp_Dir& d, QJsonObject& json) {
json["x"] = d.X();
json["y"] = d.Y();
json["z"] = d.Z();
}
gp_Dir jsonToGpDir(const QJsonObject& json) {
return gp_Dir(json["x"].toDouble(), json["y"].toDouble(), json["z"].toDouble());
}
}
SketchFeature::SketchFeature(const QString& name) SketchFeature::SketchFeature(const QString& name)
: Feature(name) : Feature(name), m_plane(gp_Pnt(0, 0, 0), gp::DZ())
{ {
BRep_Builder builder;
TopoDS_Compound compound;
builder.MakeCompound(compound);
m_shape = compound;
} }
SketchFeature::~SketchFeature() SketchFeature::~SketchFeature()
@@ -27,12 +60,12 @@ QString SketchFeature::type() const
return "Sketch"; return "Sketch";
} }
void SketchFeature::setPlane(SketchPlane plane) void SketchFeature::setPlane(const gp_Ax2& plane)
{ {
m_plane = plane; m_plane = plane;
} }
SketchFeature::SketchPlane SketchFeature::plane() const const gp_Ax2& SketchFeature::plane() const
{ {
return m_plane; return m_plane;
} }
@@ -42,6 +75,12 @@ const TopoDS_Shape& SketchFeature::shape() const
return m_shape; return m_shape;
} }
void SketchFeature::addShape(const TopoDS_Shape& shape)
{
BRep_Builder builder;
builder.Add(m_shape, shape);
}
void SketchFeature::addObject(SketchObject* object) void SketchFeature::addObject(SketchObject* object)
{ {
m_objects.append(object); m_objects.append(object);
@@ -55,11 +94,14 @@ const QList<SketchObject*>& SketchFeature::objects() const
void SketchFeature::read(const QJsonObject& json) void SketchFeature::read(const QJsonObject& json)
{ {
Feature::read(json); Feature::read(json);
if (json.contains("plane") && json["plane"].isString()) { if (json.contains("plane") && json["plane"].isObject()) {
QString planeStr = json["plane"].toString(); QJsonObject planeJson = json["plane"].toObject();
if (planeStr == "XY") m_plane = SketchPlane::XY; if (planeJson.contains("origin") && planeJson.contains("normal") && planeJson.contains("x_direction")) {
else if (planeStr == "XZ") m_plane = SketchPlane::XZ; gp_Pnt origin = jsonToGpPnt(planeJson["origin"].toObject());
else if (planeStr == "YZ") m_plane = SketchPlane::YZ; gp_Dir normal = jsonToGpDir(planeJson["normal"].toObject());
gp_Dir x_dir = jsonToGpDir(planeJson["x_direction"].toObject());
m_plane = gp_Ax2(origin, normal, x_dir);
}
} }
if (json.contains("objects") && json["objects"].isArray()) { if (json.contains("objects") && json["objects"].isArray()) {
@@ -87,13 +129,22 @@ void SketchFeature::read(const QJsonObject& json)
void SketchFeature::write(QJsonObject& json) const void SketchFeature::write(QJsonObject& json) const
{ {
Feature::write(json); Feature::write(json);
QString planeStr;
switch (m_plane) { QJsonObject planeJson;
case SketchPlane::XY: planeStr = "XY"; break;
case SketchPlane::XZ: planeStr = "XZ"; break; QJsonObject originJson;
case SketchPlane::YZ: planeStr = "YZ"; break; gpPntToJson(m_plane.Location(), originJson);
} planeJson["origin"] = originJson;
json["plane"] = planeStr;
QJsonObject normalJson;
gpDirToJson(m_plane.Direction(), normalJson);
planeJson["normal"] = normalJson;
QJsonObject xDirJson;
gpDirToJson(m_plane.XDirection(), xDirJson);
planeJson["x_direction"] = xDirJson;
json["plane"] = planeJson;
QJsonArray objectsArray; QJsonArray objectsArray;
for (const auto& object : m_objects) { for (const auto& object : m_objects) {
+5 -9
View File
@@ -9,6 +9,7 @@
#define SKETCHFEATURE_H #define SKETCHFEATURE_H
#include <TopoDS_Shape.hxx> #include <TopoDS_Shape.hxx>
#include <gp_Ax2.hxx>
#include <QList> #include <QList>
#include "Feature.h" #include "Feature.h"
@@ -17,21 +18,16 @@ class SketchObject;
class SketchFeature : public Feature class SketchFeature : public Feature
{ {
public: public:
enum class SketchPlane {
XY,
XZ,
YZ
};
SketchFeature(const QString& name); SketchFeature(const QString& name);
~SketchFeature(); ~SketchFeature();
QString type() const override; QString type() const override;
void setPlane(SketchPlane plane); void setPlane(const gp_Ax2& plane);
SketchPlane plane() const; const gp_Ax2& plane() const;
const TopoDS_Shape& shape() const; const TopoDS_Shape& shape() const;
void addShape(const TopoDS_Shape& shape);
void addObject(SketchObject* object); void addObject(SketchObject* object);
const QList<SketchObject*>& objects() const; const QList<SketchObject*>& objects() const;
@@ -40,7 +36,7 @@ public:
void write(QJsonObject &json) const override; void write(QJsonObject &json) const override;
private: private:
SketchPlane m_plane; gp_Ax2 m_plane;
TopoDS_Shape m_shape; TopoDS_Shape m_shape;
QList<SketchObject*> m_objects; QList<SketchObject*> m_objects;
}; };
+55 -50
View File
@@ -13,6 +13,7 @@
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QPainter> #include <QPainter>
#include <QVector> #include <QVector>
#include <gp_Ax2.hxx>
namespace { namespace {
struct GridParams { struct GridParams {
@@ -62,7 +63,7 @@ void SketchGrid::initializeGL()
m_vbo.release(); m_vbo.release();
} }
void SketchGrid::paintGL(SketchPlane plane, QOpenGLShaderProgram* shaderProgram, int colorLoc) void SketchGrid::paintGL(const gp_Ax2& plane, QOpenGLShaderProgram* shaderProgram, int colorLoc)
{ {
GLint previous_vao = 0; GLint previous_vao = 0;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &previous_vao); glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &previous_vao);
@@ -77,12 +78,19 @@ void SketchGrid::paintGL(SketchPlane plane, QOpenGLShaderProgram* shaderProgram,
QOpenGLContext::currentContext()->extraFunctions()->glBindVertexArray(previous_vao); QOpenGLContext::currentContext()->extraFunctions()->glBindVertexArray(previous_vao);
} }
void SketchGrid::drawGridLines(SketchPlane plane, QOpenGLShaderProgram* shaderProgram, int colorLoc) void SketchGrid::drawGridLines(const gp_Ax2& plane, QOpenGLShaderProgram* shaderProgram, int colorLoc)
{ {
auto params = getGridParams(-m_viewport->camera()->uiCameraDistance()); auto params = getGridParams(-m_viewport->camera()->uiCameraDistance());
const float minorIncrement = params.minorIncrement; const float minorIncrement = params.minorIncrement;
const int gridSize = params.gridSize; const int gridSize = params.gridSize;
const auto& origin = plane.Location();
const auto& xDir = plane.XDirection();
const auto& yDir = plane.YDirection();
QVector3D originVec(origin.X(), origin.Y(), origin.Z());
QVector3D xDirVec(xDir.X(), xDir.Y(), xDir.Z());
QVector3D yDirVec(yDir.X(), yDir.Y(), yDir.Z());
QVector<GLfloat> minorLines; QVector<GLfloat> minorLines;
QVector<GLfloat> majorLines; QVector<GLfloat> majorLines;
@@ -93,16 +101,14 @@ void SketchGrid::drawGridLines(SketchPlane plane, QOpenGLShaderProgram* shaderPr
float pos = i * minorIncrement; float pos = i * minorIncrement;
QVector<GLfloat>& current_vector = (i % 5 == 0) ? majorLines : minorLines; QVector<GLfloat>& current_vector = (i % 5 == 0) ? majorLines : minorLines;
if (plane == XY) {
current_vector << pos << -gridSize << 0 << pos << gridSize << 0; QVector3D p1 = originVec + pos * xDirVec - gridSize * yDirVec;
current_vector << -gridSize << pos << 0 << gridSize << pos << 0; QVector3D p2 = originVec + pos * xDirVec + gridSize * yDirVec;
} else if (plane == XZ) { current_vector << p1.x() << p1.y() << p1.z() << p2.x() << p2.y() << p2.z();
current_vector << pos << 0 << -gridSize << pos << 0 << gridSize;
current_vector << -gridSize << 0 << pos << gridSize << 0 << pos; QVector3D p3 = originVec - gridSize * xDirVec + pos * yDirVec;
} else { // YZ QVector3D p4 = originVec + gridSize * xDirVec + pos * yDirVec;
current_vector << 0 << pos << -gridSize << 0 << pos << gridSize; current_vector << p3.x() << p3.y() << p3.z() << p4.x() << p4.y() << p4.z();
current_vector << 0 << -gridSize << pos << 0 << gridSize << pos;
}
} }
m_vbo.bind(); m_vbo.bind();
@@ -120,50 +126,51 @@ void SketchGrid::drawGridLines(SketchPlane plane, QOpenGLShaderProgram* shaderPr
glDrawArrays(GL_LINES, 0, majorLines.size() / 3); glDrawArrays(GL_LINES, 0, majorLines.size() / 3);
} }
void SketchGrid::drawAxes(SketchPlane plane, QOpenGLShaderProgram* shaderProgram, int colorLoc) void SketchGrid::drawAxes(const gp_Ax2& plane, QOpenGLShaderProgram* shaderProgram, int colorLoc)
{ {
auto params = getGridParams(-m_viewport->camera()->uiCameraDistance()); auto params = getGridParams(-m_viewport->camera()->uiCameraDistance());
const int axisLength = params.gridSize; const int axisLength = params.gridSize;
const auto& origin = plane.Location();
const auto& xDir = plane.XDirection();
const auto& yDir = plane.YDirection();
QVector3D originVec(origin.X(), origin.Y(), origin.Z());
QVector3D xDirVec(xDir.X(), xDir.Y(), xDir.Z());
QVector3D yDirVec(yDir.X(), yDir.Y(), yDir.Z());
QVector<GLfloat> vertices; QVector<GLfloat> vertices;
glLineWidth(2.0f); glLineWidth(2.0f);
m_vbo.bind(); m_vbo.bind();
// X Axis (Red) // X Axis (Red)
if (plane == XY || plane == XZ) { vertices.clear();
vertices.clear(); QVector3D p1 = originVec - axisLength * xDirVec;
vertices << -axisLength << 0 << 0 << axisLength << 0 << 0; QVector3D p2 = originVec + axisLength * xDirVec;
shaderProgram->setUniformValue(colorLoc, QVector4D(1.0f, 0.0f, 0.0f, 1.0f)); vertices << p1.x() << p1.y() << p1.z() << p2.x() << p2.y() << p2.z();
m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat)); shaderProgram->setUniformValue(colorLoc, QVector4D(1.0f, 0.0f, 0.0f, 1.0f));
glDrawArrays(GL_LINES, 0, 2); m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
} glDrawArrays(GL_LINES, 0, 2);
// Y Axis (Green) // Y Axis (Green)
if (plane == XY || plane == YZ) { vertices.clear();
vertices.clear(); QVector3D p3 = originVec - axisLength * yDirVec;
vertices << 0 << -axisLength << 0 << 0 << axisLength << 0; QVector3D p4 = originVec + axisLength * yDirVec;
shaderProgram->setUniformValue(colorLoc, QVector4D(0.0f, 1.0f, 0.0f, 1.0f)); vertices << p3.x() << p3.y() << p3.z() << p4.x() << p4.y() << p4.z();
m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat)); shaderProgram->setUniformValue(colorLoc, QVector4D(0.0f, 1.0f, 0.0f, 1.0f));
glDrawArrays(GL_LINES, 0, 2); m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
} glDrawArrays(GL_LINES, 0, 2);
// Z Axis (Blue)
if (plane == XZ || plane == YZ) {
vertices.clear();
vertices << 0 << 0 << -axisLength << 0 << 0 << axisLength;
shaderProgram->setUniformValue(colorLoc, QVector4D(0.0f, 0.0f, 1.0f, 1.0f));
m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
glDrawArrays(GL_LINES, 0, 2);
}
// Origin dot // Origin dot
glPointSize(5.0f); glPointSize(5.0f);
vertices.clear(); vertices.clear();
vertices << 0.0f << 0.0f << 0.0f; vertices << originVec.x() << originVec.y() << originVec.z();
shaderProgram->setUniformValue(colorLoc, QVector4D(1.0f, 1.0f, 1.0f, 1.0f)); // White shaderProgram->setUniformValue(colorLoc, QVector4D(1.0f, 1.0f, 1.0f, 1.0f)); // White
m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat)); m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
glDrawArrays(GL_POINTS, 0, 1); glDrawArrays(GL_POINTS, 0, 1);
} }
void SketchGrid::paintAxisLabels(QPainter& painter, SketchGrid::SketchPlane plane, const QMatrix4x4& modelView, const QMatrix4x4& projection) void SketchGrid::paintAxisLabels(QPainter& painter, const gp_Ax2& plane, const QMatrix4x4& modelView, const QMatrix4x4& projection)
{ {
painter.setPen(Qt::white); painter.setPen(Qt::white);
painter.setFont(QFont("Arial", 10)); painter.setFont(QFont("Arial", 10));
@@ -172,15 +179,21 @@ void SketchGrid::paintAxisLabels(QPainter& painter, SketchGrid::SketchPlane plan
const float majorIncrement = params.majorIncrement; const float majorIncrement = params.majorIncrement;
const int range = params.gridSize; const int range = params.gridSize;
auto drawLabelsForAxis = [&](int axis_idx) { const auto& origin = plane.Location();
const auto& xDir = plane.XDirection();
const auto& yDir = plane.YDirection();
QVector3D originVec(origin.X(), origin.Y(), origin.Z());
QVector3D xDirVec(xDir.X(), xDir.Y(), xDir.Z());
QVector3D yDirVec(yDir.X(), yDir.Y(), yDir.Z());
auto drawLabelsForAxis = [&](const QVector3D& axisDir) {
int numLabels = range / majorIncrement; int numLabels = range / majorIncrement;
for (int i = -numLabels; i <= numLabels; ++i) { for (int i = -numLabels; i <= numLabels; ++i) {
if (i == 0) if (i == 0)
continue; continue;
float val = i * majorIncrement; float val = i * majorIncrement;
QVector3D worldCoord; QVector3D worldCoord = originVec + val * axisDir;
worldCoord[axis_idx] = val;
QVector3D screenPos = m_viewport->project(worldCoord, modelView, projection, m_viewport->rect()); QVector3D screenPos = m_viewport->project(worldCoord, modelView, projection, m_viewport->rect());
if (screenPos.z() < 1.0f) { // Not clipped if (screenPos.z() < 1.0f) { // Not clipped
@@ -189,14 +202,6 @@ void SketchGrid::paintAxisLabels(QPainter& painter, SketchGrid::SketchPlane plan
} }
}; };
if (plane == SketchGrid::XY) { drawLabelsForAxis(xDirVec);
drawLabelsForAxis(0); // X drawLabelsForAxis(yDirVec);
drawLabelsForAxis(1); // Y
} else if (plane == SketchGrid::XZ) {
drawLabelsForAxis(0); // X
drawLabelsForAxis(2); // Z
} else if (plane == SketchGrid::YZ) {
drawLabelsForAxis(1); // Y
drawLabelsForAxis(2); // Z
}
} }
+5 -10
View File
@@ -12,6 +12,7 @@
#include <QMatrix4x4> #include <QMatrix4x4>
#include <QOpenGLVertexArrayObject> #include <QOpenGLVertexArrayObject>
#include <QOpenGLBuffer> #include <QOpenGLBuffer>
#include <gp_Ax2.hxx>
class QOpenGLShaderProgram; class QOpenGLShaderProgram;
class QPainter; class QPainter;
@@ -20,22 +21,16 @@ class ViewportWidget;
class SketchGrid : protected QOpenGLFunctions class SketchGrid : protected QOpenGLFunctions
{ {
public: public:
enum SketchPlane {
XY = 1,
XZ = 2,
YZ = 3
};
explicit SketchGrid(ViewportWidget* viewport); explicit SketchGrid(ViewportWidget* viewport);
~SketchGrid(); ~SketchGrid();
void initializeGL(); void initializeGL();
void paintGL(SketchPlane plane, QOpenGLShaderProgram* shaderProgram, int colorLoc); void paintGL(const gp_Ax2& plane, QOpenGLShaderProgram* shaderProgram, int colorLoc);
void paintAxisLabels(QPainter& painter, SketchPlane plane, const QMatrix4x4& modelView, const QMatrix4x4& projection); void paintAxisLabels(QPainter& painter, const gp_Ax2& plane, const QMatrix4x4& modelView, const QMatrix4x4& projection);
private: private:
void drawGridLines(SketchPlane plane, QOpenGLShaderProgram* shaderProgram, int colorLoc); void drawGridLines(const gp_Ax2& plane, QOpenGLShaderProgram* shaderProgram, int colorLoc);
void drawAxes(SketchPlane plane, QOpenGLShaderProgram* shaderProgram, int colorLoc); void drawAxes(const gp_Ax2& plane, QOpenGLShaderProgram* shaderProgram, int colorLoc);
QOpenGLVertexArrayObject m_vao; QOpenGLVertexArrayObject m_vao;
QOpenGLBuffer m_vbo; QOpenGLBuffer m_vbo;
+62 -90
View File
@@ -19,6 +19,11 @@
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QVector> #include <QVector>
#include <QtMath> #include <QtMath>
#include <optional>
#include <gp_Ax2.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Vec.hxx>
#include <ElCLib.hxx>
Snapping::Snapping(ViewportWidget* viewport) : m_viewport(viewport) Snapping::Snapping(ViewportWidget* viewport) : m_viewport(viewport)
{ {
@@ -30,23 +35,15 @@ bool Snapping::update(const QPoint& mousePos)
bool oldIsSnappingVertex = m_isSnappingVertex; bool oldIsSnappingVertex = m_isSnappingVertex;
bool shouldSnap = false; bool shouldSnap = false;
if (m_viewport->currentPlane() != ViewportWidget::SketchPlane::NONE && m_viewport->activeTool() != static_cast<int>(ApplicationController::ToolType::None)) { auto currentPlaneOpt = m_viewport->currentPlane();
QVector3D worldPos = m_viewport->unproject(mousePos, m_viewport->currentPlane()); if (currentPlaneOpt && m_viewport->activeTool() != static_cast<int>(ApplicationController::ToolType::None)) {
const auto& plane = currentPlaneOpt.value();
QVector3D worldPosQ = m_viewport->unproject(mousePos, plane);
gp_Pnt worldPos(worldPosQ.x(), worldPosQ.y(), worldPosQ.z());
const float snapRectHalfSize = 0.0075f * -m_viewport->camera()->zoom(); const float snapRectHalfSize = 0.0075f * -m_viewport->camera()->zoom();
switch (m_viewport->currentPlane()) { gp_Pnt2d worldPos2d(gp_Vec(plane.Location(), worldPos).Dot(plane.XDirection()), gp_Vec(plane.Location(), worldPos).Dot(plane.YDirection()));
case ViewportWidget::SketchPlane::XY: shouldSnap = qAbs(worldPos2d.X()) < snapRectHalfSize && qAbs(worldPos2d.Y()) < snapRectHalfSize;
shouldSnap = qAbs(worldPos.x()) < snapRectHalfSize && qAbs(worldPos.y()) < snapRectHalfSize;
break;
case ViewportWidget::SketchPlane::XZ:
shouldSnap = qAbs(worldPos.x()) < snapRectHalfSize && qAbs(worldPos.z()) < snapRectHalfSize;
break;
case ViewportWidget::SketchPlane::YZ:
shouldSnap = qAbs(worldPos.y()) < snapRectHalfSize && qAbs(worldPos.z()) < snapRectHalfSize;
break;
case ViewportWidget::SketchPlane::NONE:
break;
}
} }
m_isSnappingOrigin = shouldSnap; m_isSnappingOrigin = shouldSnap;
@@ -55,8 +52,11 @@ bool Snapping::update(const QPoint& mousePos)
} }
m_isSnappingVertex = false; m_isSnappingVertex = false;
if (!m_isSnappingOrigin && m_viewport->document() && m_viewport->currentPlane() != ViewportWidget::SketchPlane::NONE && m_viewport->activeTool() != static_cast<int>(ApplicationController::ToolType::None)) { if (!m_isSnappingOrigin && m_viewport->document() && currentPlaneOpt && m_viewport->activeTool() != static_cast<int>(ApplicationController::ToolType::None)) {
QVector3D worldPos = m_viewport->unproject(mousePos, m_viewport->currentPlane()); const auto& plane = currentPlaneOpt.value();
QVector3D worldPosQ = m_viewport->unproject(mousePos, plane);
gp_Pnt worldPos(worldPosQ.x(), worldPosQ.y(), worldPosQ.z());
gp_Pnt2d worldPos2d(gp_Vec(plane.Location(), worldPos).Dot(plane.XDirection()), gp_Vec(plane.Location(), worldPos).Dot(plane.YDirection()));
const float snapRectHalfSize = 0.0075f * -m_viewport->camera()->zoom(); const float snapRectHalfSize = 0.0075f * -m_viewport->camera()->zoom();
for (Feature* feature : m_viewport->document()->features()) { for (Feature* feature : m_viewport->document()->features()) {
@@ -66,20 +66,8 @@ bool Snapping::update(const QPoint& mousePos)
auto line = static_cast<const SketchLine*>(obj); auto line = static_cast<const SketchLine*>(obj);
const gp_Pnt vertices[] = {line->startPoint(), line->endPoint()}; const gp_Pnt vertices[] = {line->startPoint(), line->endPoint()};
for (const auto& vertex : vertices) { for (const auto& vertex : vertices) {
bool isClose = false; gp_Pnt2d vertex2d(gp_Vec(plane.Location(), vertex).Dot(plane.XDirection()), gp_Vec(plane.Location(), vertex).Dot(plane.YDirection()));
switch (m_viewport->currentPlane()) { bool isClose = qAbs(worldPos2d.X() - vertex2d.X()) < snapRectHalfSize && qAbs(worldPos2d.Y() - vertex2d.Y()) < snapRectHalfSize;
case ViewportWidget::SketchPlane::XY:
isClose = qAbs(worldPos.x() - vertex.X()) < snapRectHalfSize && qAbs(worldPos.y() - vertex.Y()) < snapRectHalfSize;
break;
case ViewportWidget::SketchPlane::XZ:
isClose = qAbs(worldPos.x() - vertex.X()) < snapRectHalfSize && qAbs(worldPos.z() - vertex.Z()) < snapRectHalfSize;
break;
case ViewportWidget::SketchPlane::YZ:
isClose = qAbs(worldPos.y() - vertex.Y()) < snapRectHalfSize && qAbs(worldPos.z() - vertex.Z()) < snapRectHalfSize;
break;
case ViewportWidget::SketchPlane::NONE:
break;
}
if (isClose) { if (isClose) {
m_isSnappingVertex = true; m_isSnappingVertex = true;
@@ -89,37 +77,23 @@ bool Snapping::update(const QPoint& mousePos)
} }
} else if (obj->type() == SketchObject::ObjectType::Rectangle) { } else if (obj->type() == SketchObject::ObjectType::Rectangle) {
auto rect = static_cast<const SketchRectangle*>(obj); auto rect = static_cast<const SketchRectangle*>(obj);
const auto& rectPlane = sketch->plane();
const auto& p1 = rect->corner1(); const auto& p1 = rect->corner1();
const auto& p3 = rect->corner2(); const auto& p3 = rect->corner2();
gp_Pnt p2, p4;
if (sketch->plane() == SketchFeature::SketchPlane::XY) { gp_Pnt2d p1_2d(gp_Vec(rectPlane.Location(), p1).Dot(rectPlane.XDirection()), gp_Vec(rectPlane.Location(), p1).Dot(rectPlane.YDirection()));
p2.SetCoord(p3.X(), p1.Y(), p1.Z()); gp_Pnt2d p3_2d(gp_Vec(rectPlane.Location(), p3).Dot(rectPlane.XDirection()), gp_Vec(rectPlane.Location(), p3).Dot(rectPlane.YDirection()));
p4.SetCoord(p1.X(), p3.Y(), p1.Z());
} else if (sketch->plane() == SketchFeature::SketchPlane::XZ) { gp_Pnt2d p2_2d(p3_2d.X(), p1_2d.Y());
p2.SetCoord(p3.X(), p1.Y(), p1.Z()); gp_Pnt2d p4_2d(p1_2d.X(), p3_2d.Y());
p4.SetCoord(p1.X(), p1.Y(), p3.Z());
} else if (sketch->plane() == SketchFeature::SketchPlane::YZ) { gp_Pnt p2 = ElCLib::To3d(rectPlane, p2_2d);
p2.SetCoord(p1.X(), p3.Y(), p1.Z()); gp_Pnt p4 = ElCLib::To3d(rectPlane, p4_2d);
p4.SetCoord(p1.X(), p1.Y(), p3.Z());
}
const gp_Pnt vertices[] = {p1, p2, p3, p4}; const gp_Pnt vertices[] = {p1, p2, p3, p4};
for (const auto& vertex : vertices) { for (const auto& vertex : vertices) {
bool isClose = false; gp_Pnt2d vertex2d(gp_Vec(plane.Location(), vertex).Dot(plane.XDirection()), gp_Vec(plane.Location(), vertex).Dot(plane.YDirection()));
switch (m_viewport->currentPlane()) { bool isClose = qAbs(worldPos2d.X() - vertex2d.X()) < snapRectHalfSize && qAbs(worldPos2d.Y() - vertex2d.Y()) < snapRectHalfSize;
case ViewportWidget::SketchPlane::XY:
isClose = qAbs(worldPos.x() - vertex.X()) < snapRectHalfSize && qAbs(worldPos.y() - vertex.Y()) < snapRectHalfSize;
break;
case ViewportWidget::SketchPlane::XZ:
isClose = qAbs(worldPos.x() - vertex.X()) < snapRectHalfSize && qAbs(worldPos.z() - vertex.Z()) < snapRectHalfSize;
break;
case ViewportWidget::SketchPlane::YZ:
isClose = qAbs(worldPos.y() - vertex.Y()) < snapRectHalfSize && qAbs(worldPos.z() - vertex.Z()) < snapRectHalfSize;
break;
case ViewportWidget::SketchPlane::NONE:
break;
}
if (isClose) { if (isClose) {
m_isSnappingVertex = true; m_isSnappingVertex = true;
@@ -144,43 +118,41 @@ void Snapping::paintGL() const
} }
QVector<GLfloat> vertices; QVector<GLfloat> vertices;
auto currentPlaneOpt = m_viewport->currentPlane();
if (!currentPlaneOpt) {
return;
}
const auto& plane = currentPlaneOpt.value();
const auto& xDir = plane.XDirection();
const auto& yDir = plane.YDirection();
QVector3D X(xDir.X(), xDir.Y(), xDir.Z());
QVector3D Y(yDir.X(), yDir.Y(), yDir.Z());
const float rectSize = 0.0075f * -m_viewport->camera()->zoom();
if (m_isSnappingOrigin) { if (m_isSnappingOrigin) {
const float rectSize = 0.0075f * -m_viewport->camera()->zoom(); const auto& o = plane.Location();
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { QVector3D O(o.X(), o.Y(), o.Z());
vertices << -rectSize << -rectSize << 0 << rectSize << -rectSize << 0;
vertices << rectSize << -rectSize << 0 << rectSize << rectSize << 0; QVector3D p1 = O - rectSize * X - rectSize * Y;
vertices << rectSize << rectSize << 0 << -rectSize << rectSize << 0; QVector3D p2 = O + rectSize * X - rectSize * Y;
vertices << -rectSize << rectSize << 0 << -rectSize << -rectSize << 0; QVector3D p3 = O + rectSize * X + rectSize * Y;
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { QVector3D p4 = O - rectSize * X + rectSize * Y;
vertices << -rectSize << 0 << -rectSize << rectSize << 0 << -rectSize; vertices << p1.x() << p1.y() << p1.z() << p2.x() << p2.y() << p2.z();
vertices << rectSize << 0 << -rectSize << rectSize << 0 << rectSize; vertices << p2.x() << p2.y() << p2.z() << p3.x() << p3.y() << p3.z();
vertices << rectSize << 0 << rectSize << -rectSize << 0 << rectSize; vertices << p3.x() << p3.y() << p3.z() << p4.x() << p4.y() << p4.z();
vertices << -rectSize << 0 << rectSize << -rectSize << 0 << -rectSize; vertices << p4.x() << p4.y() << p4.z() << p1.x() << p1.y() << p1.z();
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) {
vertices << 0 << -rectSize << -rectSize << 0 << rectSize << -rectSize;
vertices << 0 << rectSize << -rectSize << 0 << rectSize << rectSize;
vertices << 0 << rectSize << rectSize << 0 << -rectSize << rectSize;
vertices << 0 << -rectSize << rectSize << 0 << -rectSize << -rectSize;
}
} else if (m_isSnappingVertex) { } else if (m_isSnappingVertex) {
const float rectSize = 0.0075f * -m_viewport->camera()->zoom();
const auto& v = m_snapVertex; const auto& v = m_snapVertex;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { QVector3D V(v.X(), v.Y(), v.Z());
vertices << v.X() - rectSize << v.Y() - rectSize << v.Z() << v.X() + rectSize << v.Y() - rectSize << v.Z();
vertices << v.X() + rectSize << v.Y() - rectSize << v.Z() << v.X() + rectSize << v.Y() + rectSize << v.Z(); QVector3D p1 = V - rectSize * X - rectSize * Y;
vertices << v.X() + rectSize << v.Y() + rectSize << v.Z() << v.X() - rectSize << v.Y() + rectSize << v.Z(); QVector3D p2 = V + rectSize * X - rectSize * Y;
vertices << v.X() - rectSize << v.Y() + rectSize << v.Z() << v.X() - rectSize << v.Y() - rectSize << v.Z(); QVector3D p3 = V + rectSize * X + rectSize * Y;
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) { QVector3D p4 = V - rectSize * X + rectSize * Y;
vertices << v.X() - rectSize << v.Y() << v.Z() - rectSize << v.X() + rectSize << v.Y() << v.Z() - rectSize; vertices << p1.x() << p1.y() << p1.z() << p2.x() << p2.y() << p2.z();
vertices << v.X() + rectSize << v.Y() << v.Z() - rectSize << v.X() + rectSize << v.Y() << v.Z() + rectSize; vertices << p2.x() << p2.y() << p2.z() << p3.x() << p3.y() << p3.z();
vertices << v.X() + rectSize << v.Y() << v.Z() + rectSize << v.X() - rectSize << v.Y() << v.Z() + rectSize; vertices << p3.x() << p3.y() << p3.z() << p4.x() << p4.y() << p4.z();
vertices << v.X() - rectSize << v.Y() << v.Z() + rectSize << v.X() - rectSize << v.Y() << v.Z() - rectSize; vertices << p4.x() << p4.y() << p4.z() << p1.x() << p1.y() << p1.z();
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) {
vertices << v.X() << v.Y() - rectSize << v.Z() - rectSize << v.X() << v.Y() + rectSize << v.Z() - rectSize;
vertices << v.X() << v.Y() + rectSize << v.Z() - rectSize << v.X() << v.Y() + rectSize << v.Z() + rectSize;
vertices << v.X() << v.Y() + rectSize << v.Z() + rectSize << v.X() << v.Y() - rectSize << v.Z() + rectSize;
vertices << v.X() << v.Y() - rectSize << v.Z() + rectSize << v.X() << v.Y() - rectSize << v.Z() - rectSize;
}
} }
m_viewport->shaderProgram()->setUniformValue(m_viewport->colorLoc(), QVector4D(1.0f, 1.0f, 0.0f, 0.5f)); m_viewport->shaderProgram()->setUniformValue(m_viewport->colorLoc(), QVector4D(1.0f, 1.0f, 0.0f, 0.5f));
m_viewport->vbo().bind(); m_viewport->vbo().bind();
+90 -82
View File
@@ -33,9 +33,15 @@
#include <QApplication> #include <QApplication>
#include <cmath> #include <cmath>
#include <QtMath> #include <QtMath>
#include <ElCLib.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Vec.hxx>
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QVector> #include <QVector>
#include <map> #include <map>
#include <optional>
#include <gp_Ax2.hxx>
#include <gp_Dir.hxx>
struct PntComparator { struct PntComparator {
bool operator()(const gp_Pnt& a, const gp_Pnt& b) const { bool operator()(const gp_Pnt& a, const gp_Pnt& b) const {
@@ -60,7 +66,7 @@ ViewportWidget::ViewportWidget(QWidget *parent)
setMouseTracking(true); setMouseTracking(true);
setFocusPolicy(Qt::StrongFocus); setFocusPolicy(Qt::StrongFocus);
m_currentPlane = SketchPlane::XY; m_currentPlane = gp_Ax2(gp::Origin(), gp::DZ());
m_toolIcons.insert(static_cast<int>(ApplicationController::ToolType::Line), new QSvgRenderer(QString(":/icons/line.svg"), this)); m_toolIcons.insert(static_cast<int>(ApplicationController::ToolType::Line), new QSvgRenderer(QString(":/icons/line.svg"), this));
m_toolIcons.insert(static_cast<int>(ApplicationController::ToolType::Rectangle), new QSvgRenderer(QString(":/icons/rectangle.svg"), this)); m_toolIcons.insert(static_cast<int>(ApplicationController::ToolType::Rectangle), new QSvgRenderer(QString(":/icons/rectangle.svg"), this));
@@ -143,12 +149,12 @@ void ViewportWidget::paintGL()
// Sketch grid rendering // Sketch grid rendering
if (m_isSelectingPlane) { if (m_isSelectingPlane) {
if (m_highlightedPlane != SketchPlane::NONE) { if (m_highlightedPlane) {
m_sketchGrid->paintGL(static_cast<SketchGrid::SketchPlane>(m_highlightedPlane), m_shaderProgram, m_colorLoc); m_sketchGrid->paintGL(m_highlightedPlane.value(), m_shaderProgram, m_colorLoc);
} }
} }
if (m_currentPlane != SketchPlane::NONE) { if (m_currentPlane) {
m_sketchGrid->paintGL(static_cast<SketchGrid::SketchPlane>(m_currentPlane), m_shaderProgram, m_colorLoc); m_sketchGrid->paintGL(m_currentPlane.value(), m_shaderProgram, m_colorLoc);
} }
if (m_isSelectingPlane) { if (m_isSelectingPlane) {
@@ -205,8 +211,8 @@ void ViewportWidget::paintGL()
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
QPainter painter(this); QPainter painter(this);
if (m_currentPlane != SketchPlane::NONE) { if (m_currentPlane) {
m_sketchGrid->paintAxisLabels(painter, static_cast<SketchGrid::SketchPlane>(m_currentPlane), model, projection); m_sketchGrid->paintAxisLabels(painter, m_currentPlane.value(), model, projection);
} }
m_featureBrowser->paint(painter, width(), height()); m_featureBrowser->paint(painter, width(), height());
m_viewCube->paint2D(painter, width(), height()); m_viewCube->paint2D(painter, width(), height());
@@ -233,8 +239,10 @@ void ViewportWidget::mousePressEvent(QMouseEvent *event)
m_camera->mousePressEvent(event); m_camera->mousePressEvent(event);
if (event->button() == Qt::MiddleButton && !(QApplication::keyboardModifiers() & Qt::ShiftModifier)) { if (event->button() == Qt::MiddleButton && !(QApplication::keyboardModifiers() & Qt::ShiftModifier)) {
m_camera->startRotation(unproject(event->pos(), m_currentPlane)); if (m_currentPlane) {
update(); m_camera->startRotation(unproject(event->pos(), m_currentPlane.value()));
update();
}
} }
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
@@ -245,10 +253,10 @@ void ViewportWidget::mousePressEvent(QMouseEvent *event)
} }
if (m_isSelectingPlane) { if (m_isSelectingPlane) {
if (m_highlightedPlane != SketchPlane::NONE) { if (m_highlightedPlane) {
emit planeSelected(m_highlightedPlane); emit planeSelected(m_highlightedPlane.value());
m_isSelectingPlane = false; m_isSelectingPlane = false;
m_highlightedPlane = SketchPlane::NONE; m_highlightedPlane.reset();
update(); update();
} }
return; return;
@@ -268,8 +276,17 @@ void ViewportWidget::mouseMoveEvent(QMouseEvent *event)
m_currentMousePos = event->pos(); m_currentMousePos = event->pos();
if (m_isSelectingPlane) { if (m_isSelectingPlane) {
SketchPlane newHighlight = checkPlaneSelection(m_currentMousePos); auto newHighlight = checkPlaneSelection(m_currentMousePos);
if (newHighlight != m_highlightedPlane) { bool needsUpdate = newHighlight.has_value() != m_highlightedPlane.has_value();
if (!needsUpdate && newHighlight) {
// Very basic check, assumes planes are one of the 3 cardinal ones
// and checkPlaneSelection returns them consistently.
if (!newHighlight->Direction().IsEqual(m_highlightedPlane->Direction(), 1e-9)) {
needsUpdate = true;
}
}
if (needsUpdate) {
m_highlightedPlane = newHighlight; m_highlightedPlane = newHighlight;
update(); update();
} }
@@ -289,8 +306,10 @@ void ViewportWidget::mouseMoveEvent(QMouseEvent *event)
void ViewportWidget::wheelEvent(QWheelEvent *event) void ViewportWidget::wheelEvent(QWheelEvent *event)
{ {
QVector3D worldPos = unproject(event->position().toPoint(), m_currentPlane); if (m_currentPlane) {
m_camera->wheelEvent(event, worldPos); QVector3D worldPos = unproject(event->position().toPoint(), m_currentPlane.value());
m_camera->wheelEvent(event, worldPos);
}
} }
void ViewportWidget::keyPressEvent(QKeyEvent *event) void ViewportWidget::keyPressEvent(QKeyEvent *event)
@@ -303,8 +322,8 @@ void ViewportWidget::keyPressEvent(QKeyEvent *event)
if (event->key() == Qt::Key_Escape) { if (event->key() == Qt::Key_Escape) {
if (m_isSelectingPlane) { if (m_isSelectingPlane) {
m_isSelectingPlane = false; m_isSelectingPlane = false;
m_highlightedPlane = SketchPlane::NONE; m_highlightedPlane.reset();
m_currentPlane = SketchPlane::XY; m_currentPlane = gp_Ax2(gp::Origin(), gp::DZ());
update(); update();
return; return;
} }
@@ -369,19 +388,19 @@ bool ViewportWidget::focusNextPrevChild(bool next)
return QOpenGLWidget::focusNextPrevChild(next); return QOpenGLWidget::focusNextPrevChild(next);
} }
void ViewportWidget::onSketchModeStarted(SketchPlane plane) void ViewportWidget::onSketchModeStarted(const gp_Ax2& plane)
{ {
m_currentPlane = plane; m_currentPlane = plane;
m_camera->saveState(); m_camera->saveState();
m_camera->animateToPlaneView(static_cast<int>(plane)); m_camera->animateToPlaneView(plane);
} }
void ViewportWidget::onPlaneSelectionModeStarted() void ViewportWidget::onPlaneSelectionModeStarted()
{ {
m_isSelectingPlane = true; m_isSelectingPlane = true;
m_highlightedPlane = SketchPlane::NONE; m_highlightedPlane.reset();
m_currentPlane = SketchPlane::NONE; m_currentPlane.reset();
update(); update();
} }
@@ -393,7 +412,7 @@ void ViewportWidget::onSketchModeEnded()
void ViewportWidget::onRestoreStateAnimationFinished() void ViewportWidget::onRestoreStateAnimationFinished()
{ {
// Return to showing the base XY grid when not in a sketch // Return to showing the base XY grid when not in a sketch
m_currentPlane = SketchPlane::XY; m_currentPlane = gp_Ax2(gp::Origin(), gp::DZ());
update(); update();
} }
@@ -465,7 +484,7 @@ void ViewportWidget::onActiveToolChanged(int tool)
} }
} }
QVector3D ViewportWidget::unproject(const QPoint& screenPos, SketchPlane plane) QVector3D ViewportWidget::unproject(const QPoint& screenPos, const gp_Ax2& plane)
{ {
QMatrix4x4 model = m_camera->modelViewMatrix(); QMatrix4x4 model = m_camera->modelViewMatrix();
@@ -494,17 +513,13 @@ QVector3D ViewportWidget::unproject(const QPoint& screenPos, SketchPlane plane)
QVector3D rayOrigin(nearPoint_world); QVector3D rayOrigin(nearPoint_world);
QVector3D rayDir = (QVector3D(farPoint_world) - rayOrigin).normalized(); QVector3D rayDir = (QVector3D(farPoint_world) - rayOrigin).normalized();
QVector3D planeNormal; const auto& planeNormalDir = plane.Direction();
switch (plane) { QVector3D planeNormal(planeNormalDir.X(), planeNormalDir.Y(), planeNormalDir.Z());
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); float denom = QVector3D::dotProduct(planeNormal, rayDir);
if (qAbs(denom) > 1e-6) { if (qAbs(denom) > 1e-6) {
QVector3D p0(0,0,0); const auto& planeOriginPnt = plane.Location();
QVector3D p0(planeOriginPnt.X(), planeOriginPnt.Y(), planeOriginPnt.Z());
float t = QVector3D::dotProduct(p0 - rayOrigin, planeNormal) / denom; float t = QVector3D::dotProduct(p0 - rayOrigin, planeNormal) / denom;
return rayOrigin + t * rayDir; return rayOrigin + t * rayDir;
} }
@@ -538,20 +553,11 @@ void ViewportWidget::drawSketch(const SketchFeature* sketch)
const int numSegments = 64; const int numSegments = 64;
QVector3D u_axis, v_axis; QVector3D u_axis, v_axis;
switch (sketch->plane()) { const auto& plane = sketch->plane();
case SketchFeature::SketchPlane::XY: // Top const auto& xDir = plane.XDirection();
u_axis = QVector3D(1, 0, 0); const auto& yDir = plane.YDirection();
v_axis = QVector3D(0, 1, 0); u_axis = QVector3D(xDir.X(), xDir.Y(), xDir.Z());
break; v_axis = QVector3D(yDir.X(), yDir.Y(), yDir.Z());
case SketchFeature::SketchPlane::XZ: // Front
u_axis = QVector3D(1, 0, 0);
v_axis = QVector3D(0, 0, 1);
break;
case SketchFeature::SketchPlane::YZ: // Right
u_axis = QVector3D(0, 1, 0);
v_axis = QVector3D(0, 0, 1);
break;
}
for (int i = 0; i < numSegments; ++i) { for (int i = 0; i < numSegments; ++i) {
double angle1 = 2.0 * M_PI * double(i) / double(numSegments); double angle1 = 2.0 * M_PI * double(i) / double(numSegments);
@@ -565,34 +571,32 @@ void ViewportWidget::drawSketch(const SketchFeature* sketch)
} }
} else if (obj->type() == SketchObject::ObjectType::Rectangle) { } else if (obj->type() == SketchObject::ObjectType::Rectangle) {
auto rect = static_cast<const SketchRectangle*>(obj); auto rect = static_cast<const SketchRectangle*>(obj);
const auto& p1 = rect->corner1(); const auto& plane = sketch->plane();
const auto& p3 = rect->corner2(); const auto& p1_3d = rect->corner1();
const auto& p3_3d = rect->corner2();
gp_Pnt p2, p4; gp_Pnt2d p1_2d(gp_Vec(plane.Location(), p1_3d).Dot(plane.XDirection()), gp_Vec(plane.Location(), p1_3d).Dot(plane.YDirection()));
if (sketch->plane() == SketchFeature::SketchPlane::XY) { gp_Pnt2d p3_2d(gp_Vec(plane.Location(), p3_3d).Dot(plane.XDirection()), gp_Vec(plane.Location(), p3_3d).Dot(plane.YDirection()));
p2.SetCoord(p3.X(), p1.Y(), p1.Z());
p4.SetCoord(p1.X(), p3.Y(), p1.Z());
} else if (sketch->plane() == SketchFeature::SketchPlane::XZ) {
p2.SetCoord(p3.X(), p1.Y(), p1.Z());
p4.SetCoord(p1.X(), p1.Y(), p3.Z());
} else if (sketch->plane() == SketchFeature::SketchPlane::YZ) {
p2.SetCoord(p1.X(), p3.Y(), p1.Z());
p4.SetCoord(p1.X(), p1.Y(), p3.Z());
}
lineVertices << p1.X() << p1.Y() << p1.Z(); gp_Pnt2d p2_2d(p3_2d.X(), p1_2d.Y());
lineVertices << p2.X() << p2.Y() << p2.Z(); gp_Pnt2d p4_2d(p1_2d.X(), p3_2d.Y());
lineVertices << p2.X() << p2.Y() << p2.Z();
lineVertices << p3.X() << p3.Y() << p3.Z();
lineVertices << p3.X() << p3.Y() << p3.Z();
lineVertices << p4.X() << p4.Y() << p4.Z();
lineVertices << p4.X() << p4.Y() << p4.Z();
lineVertices << p1.X() << p1.Y() << p1.Z();
vertexCounts[p1] += 2; gp_Pnt p2_3d = ElCLib::To3d(plane, p2_2d);
vertexCounts[p2] += 2; gp_Pnt p4_3d = ElCLib::To3d(plane, p4_2d);
vertexCounts[p3] += 2;
vertexCounts[p4] += 2; lineVertices << p1_3d.X() << p1_3d.Y() << p1_3d.Z();
lineVertices << p2_3d.X() << p2_3d.Y() << p2_3d.Z();
lineVertices << p2_3d.X() << p2_3d.Y() << p2_3d.Z();
lineVertices << p3_3d.X() << p3_3d.Y() << p3_3d.Z();
lineVertices << p3_3d.X() << p3_3d.Y() << p3_3d.Z();
lineVertices << p4_3d.X() << p4_3d.Y() << p4_3d.Z();
lineVertices << p4_3d.X() << p4_3d.Y() << p4_3d.Z();
lineVertices << p1_3d.X() << p1_3d.Y() << p1_3d.Z();
vertexCounts[p1_3d] += 2;
vertexCounts[p2_3d] += 2;
vertexCounts[p3_3d] += 2;
vertexCounts[p4_3d] += 2;
} }
} }
@@ -711,52 +715,56 @@ void ViewportWidget::drawSelectionPlanes()
// XY Plane (Top) // XY Plane (Top)
QVector<GLfloat> xyQuad = { planeOffset, -planeOffset, 0, planeOffset + planeSize, -planeOffset, 0, QVector<GLfloat> xyQuad = { planeOffset, -planeOffset, 0, planeOffset + planeSize, -planeOffset, 0,
planeOffset + planeSize, -planeOffset - planeSize, 0, planeOffset, -planeOffset - planeSize, 0 }; planeOffset + planeSize, -planeOffset - planeSize, 0, planeOffset, -planeOffset - planeSize, 0 };
drawPlane(xyQuad, m_highlightedPlane == SketchPlane::XY); drawPlane(xyQuad, m_highlightedPlane && m_highlightedPlane->Direction().IsEqual(gp::DZ(), 1e-9));
// XZ Plane (Front) // XZ Plane (Front)
QVector<GLfloat> xzQuad = { planeOffset, 0, planeOffset, planeOffset + planeSize, 0, planeOffset, QVector<GLfloat> xzQuad = { planeOffset, 0, planeOffset, planeOffset + planeSize, 0, planeOffset,
planeOffset + planeSize, 0, planeOffset + planeSize, planeOffset, 0, planeOffset + planeSize }; planeOffset + planeSize, 0, planeOffset + planeSize, planeOffset, 0, planeOffset + planeSize };
drawPlane(xzQuad, m_highlightedPlane == SketchPlane::XZ); drawPlane(xzQuad, m_highlightedPlane && m_highlightedPlane->Direction().IsEqual(gp::DY(), 1e-9));
// YZ Plane (Right) // YZ Plane (Right)
QVector<GLfloat> yzQuad = { 0, -planeOffset, planeOffset, 0, -planeOffset, planeOffset + planeSize, QVector<GLfloat> yzQuad = { 0, -planeOffset, planeOffset, 0, -planeOffset, planeOffset + planeSize,
0, -planeOffset - planeSize, planeOffset + planeSize, 0, -planeOffset - planeSize, planeOffset }; 0, -planeOffset - planeSize, planeOffset + planeSize, 0, -planeOffset - planeSize, planeOffset };
drawPlane(yzQuad, m_highlightedPlane == SketchPlane::YZ); drawPlane(yzQuad, m_highlightedPlane && m_highlightedPlane->Direction().IsEqual(gp::DX(), 1e-9));
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND); glDisable(GL_BLEND);
} }
ViewportWidget::SketchPlane ViewportWidget::checkPlaneSelection(const QPoint& screenPos) std::optional<gp_Ax2> ViewportWidget::checkPlaneSelection(const QPoint& screenPos)
{ {
const float planeSize = 5.0f; const float planeSize = 5.0f;
const float planeOffset = 1.0f; const float planeOffset = 1.0f;
gp_Ax2 yzPlane(gp_Pnt(0, 0, 0), gp::DX());
gp_Ax2 xzPlane(gp_Pnt(0, 0, 0), gp::DY());
gp_Ax2 xyPlane(gp_Pnt(0, 0, 0), gp::DZ());
QVector3D intersection; QVector3D intersection;
// Check front to back to handle overlaps // Check front to back to handle overlaps
// YZ plane (Right) // YZ plane (Right)
intersection = unproject(screenPos, SketchPlane::YZ); intersection = unproject(screenPos, yzPlane);
if (intersection.y() >= -planeOffset - planeSize && intersection.y() <= -planeOffset && if (intersection.y() >= -planeOffset - planeSize && intersection.y() <= -planeOffset &&
intersection.z() >= planeOffset && intersection.z() <= planeOffset + planeSize) { intersection.z() >= planeOffset && intersection.z() <= planeOffset + planeSize) {
return SketchPlane::YZ; return gp_Ax2(gp_Pnt(0, -planeOffset, planeOffset), gp::DX());
} }
// XZ plane (Front) // XZ plane (Front)
intersection = unproject(screenPos, SketchPlane::XZ); intersection = unproject(screenPos, xzPlane);
if (intersection.x() >= planeOffset && intersection.x() <= planeOffset + planeSize && if (intersection.x() >= planeOffset && intersection.x() <= planeOffset + planeSize &&
intersection.z() >= planeOffset && intersection.z() <= planeOffset + planeSize) { intersection.z() >= planeOffset && intersection.z() <= planeOffset + planeSize) {
return SketchPlane::XZ; return gp_Ax2(gp_Pnt(planeOffset, 0, planeOffset), gp::DY());
} }
// XY plane (Top) // XY plane (Top)
intersection = unproject(screenPos, SketchPlane::XY); intersection = unproject(screenPos, xyPlane);
if (intersection.x() >= planeOffset && intersection.x() <= planeOffset + planeSize && if (intersection.x() >= planeOffset && intersection.x() <= planeOffset + planeSize &&
intersection.y() >= -planeOffset - planeSize && intersection.y() <= -planeOffset) { intersection.y() >= -planeOffset - planeSize && intersection.y() <= -planeOffset) {
return SketchPlane::XY; return gp_Ax2(gp_Pnt(planeOffset, -planeOffset, 0), gp::DZ());
} }
return SketchPlane::NONE; return std::nullopt;
} }
+9 -14
View File
@@ -15,6 +15,8 @@
#include <QVector3D> #include <QVector3D>
#include <QRect> #include <QRect>
#include <gp_Pnt.hxx> #include <gp_Pnt.hxx>
#include <gp_Ax2.hxx>
#include <optional>
#include <QMap> #include <QMap>
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject> #include <QOpenGLVertexArrayObject>
@@ -35,26 +37,19 @@ class ViewportWidget : public QOpenGLWidget, protected QOpenGLFunctions
Q_OBJECT Q_OBJECT
public: public:
enum class SketchPlane {
NONE,
XY,
XZ,
YZ
};
explicit ViewportWidget(QWidget *parent = nullptr); explicit ViewportWidget(QWidget *parent = nullptr);
~ViewportWidget(); ~ViewportWidget();
void setDocument(Document* document); void setDocument(Document* document);
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, SketchPlane plane); QVector3D unproject(const QPoint& screenPos, const gp_Ax2& plane);
QOpenGLShaderProgram* shaderProgram() { return m_shaderProgram; } QOpenGLShaderProgram* shaderProgram() { return m_shaderProgram; }
QOpenGLBuffer& vbo() { return m_vbo; } QOpenGLBuffer& vbo() { return m_vbo; }
int colorLoc() const { return m_colorLoc; } int colorLoc() const { return m_colorLoc; }
Camera* camera() const { return m_camera; } Camera* camera() const { return m_camera; }
Document* document() const { return m_document; } Document* document() const { return m_document; }
SketchPlane currentPlane() const { return m_currentPlane; } std::optional<gp_Ax2> currentPlane() const { return m_currentPlane; }
const QPoint& currentMousePos() const { return m_currentMousePos; } const QPoint& currentMousePos() const { return m_currentMousePos; }
bool isSnappingOrigin() const; bool isSnappingOrigin() const;
bool isSnappingVertex() const; bool isSnappingVertex() const;
@@ -69,7 +64,7 @@ public:
void deactivateActiveTool(); void deactivateActiveTool();
public slots: public slots:
void onSketchModeStarted(SketchPlane plane); void onSketchModeStarted(const gp_Ax2& plane);
void onSketchModeEnded(); void onSketchModeEnded();
void onPlaneSelectionModeStarted(); void onPlaneSelectionModeStarted();
void onActiveToolChanged(int tool); void onActiveToolChanged(int tool);
@@ -78,7 +73,7 @@ signals:
void lineAdded(const gp_Pnt& start, const gp_Pnt& end); void lineAdded(const gp_Pnt& start, const gp_Pnt& end);
void rectangleAdded(const gp_Pnt& corner1, const gp_Pnt& corner2); void rectangleAdded(const gp_Pnt& corner1, const gp_Pnt& corner2);
void circleAdded(const gp_Pnt& center, double radius); void circleAdded(const gp_Pnt& center, double radius);
void planeSelected(SketchPlane plane); void planeSelected(const gp_Ax2& plane);
void toolDeactivated(); void toolDeactivated();
private slots: private slots:
@@ -100,7 +95,7 @@ private:
void initShaders(); void initShaders();
void drawSketch(const SketchFeature* sketch); void drawSketch(const SketchFeature* sketch);
void drawSelectionPlanes(); void drawSelectionPlanes();
ViewportWidget::SketchPlane checkPlaneSelection(const QPoint& screenPos); std::optional<gp_Ax2> checkPlaneSelection(const QPoint& screenPos);
QMatrix4x4 projection; QMatrix4x4 projection;
QOpenGLShaderProgram* m_shaderProgram = nullptr; QOpenGLShaderProgram* m_shaderProgram = nullptr;
@@ -116,10 +111,10 @@ private:
SketchGrid* m_sketchGrid = nullptr; SketchGrid* m_sketchGrid = nullptr;
FeatureBrowser* m_featureBrowser = nullptr; FeatureBrowser* m_featureBrowser = nullptr;
Document* m_document = nullptr; Document* m_document = nullptr;
SketchPlane m_currentPlane = SketchPlane::NONE; std::optional<gp_Ax2> m_currentPlane;
bool m_isSelectingPlane = false; bool m_isSelectingPlane = false;
SketchPlane m_highlightedPlane = SketchPlane::NONE; std::optional<gp_Ax2> m_highlightedPlane;
int m_activeTool = 0; int m_activeTool = 0;
SketchTool* m_activeSketchTool = nullptr; SketchTool* m_activeSketchTool = nullptr;