Compare commits

21 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
tanner f9cac02e06 Add file headers 2026-02-20 09:28:23 -07:00
tanner 05d35bbd86 Add GPLv3 license 2026-02-20 09:28:11 -07:00
41 changed files with 997 additions and 978 deletions
+2 -2
View File
@@ -7,7 +7,7 @@
On Debian 12: On Debian 12:
```bash ```bash
$ sudo apt install cmake qt6-base-dev qt6-svg-dev libtbb-dev $ sudo apt install cmake qt6-base-dev qt6-svg-dev libtbb-dev libfontconfig1-dev
$ sudo apt install libocct-foundation-dev libocct-modeling-data-dev libocct-modeling-algorithms-dev libocct-visualization-dev $ sudo apt install libocct-foundation-dev libocct-modeling-data-dev libocct-modeling-algorithms-dev libocct-visualization-dev
$ mkdir build $ mkdir build
@@ -22,7 +22,7 @@ $ ./OpenCAD
## License ## License
This program is free and open-source software licensed under the GNU GPLv3. Please see the `LICENSE.txt` file for details. This program is free and open-source software licensed under the GNU GPLv3 (or later). Please see the `LICENSE.txt` file for details.
That means you have the right to study, change, and distribute the software and source code to anyone and for any purpose as long as you grant the same rights when distributing it. That means you have the right to study, change, and distribute the software and source code to anyone and for any purpose as long as you grant the same rights when distributing it.
+45 -17
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
@@ -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);
} }
} }
+4 -4
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
@@ -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);
+24 -20
View File
@@ -1,12 +1,13 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - 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);
+4 -2
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
@@ -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();
+48 -54
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
@@ -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,7 +148,10 @@ void CircleTool::finalizeCreation()
void CircleTool::paintGL() void CircleTool::paintGL()
{ {
if (m_isDefining) { auto currentPlaneOpt = m_viewport->currentPlane();
if (!m_isDefining || !currentPlaneOpt) return;
const auto& plane = currentPlaneOpt.value();
QVector<GLfloat> vertices; QVector<GLfloat> vertices;
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());
@@ -156,7 +166,7 @@ void CircleTool::paintGL()
if (ok) diameterFromInput = true; if (ok) diameterFromInput = true;
} }
QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), plane);
double radius; double radius;
if (diameterFromInput) { if (diameterFromInput) {
@@ -164,7 +174,8 @@ void CircleTool::paintGL()
} else { } else {
worldPos = mousePos; worldPos = mousePos;
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.setX(m_viewport->snapVertex().X()); worldPos.setY(m_viewport->snapVertex().Y()); worldPos.setZ(m_viewport->snapVertex().Z()); worldPos.setX(m_viewport->snapVertex().X()); worldPos.setY(m_viewport->snapVertex().Y()); worldPos.setZ(m_viewport->snapVertex().Z());
} }
@@ -172,34 +183,18 @@ void CircleTool::paintGL()
} }
const int segments = 64; 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) { for (int i = 0; i < segments; ++i) {
double angle1 = i * 2.0 * M_PI / segments; double angle1 = i * 2.0 * M_PI / segments;
double angle2 = (i + 1) * 2.0 * M_PI / segments; double angle2 = (i + 1) * 2.0 * M_PI / segments;
QVector3D p1, p2; QVector3D p1 = centerPos + radius * (qCos(angle1) * u_axis + qSin(angle1) * v_axis);
QVector3D p2 = centerPos + radius * (qCos(angle2) * u_axis + qSin(angle2) * v_axis);
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 << p1.x() << p1.y() << p1.z();
vertices << p2.x() << p2.y() << p2.z(); vertices << p2.x() << p2.y() << p2.z();
} }
@@ -209,11 +204,13 @@ void CircleTool::paintGL()
m_viewport->vbo().allocate(vertices.constData(), vertices.size() * sizeof(GLfloat)); m_viewport->vbo().allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
glDrawArrays(GL_LINES, 0, segments * 2); 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();
if (!m_isDefining || !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());
@@ -227,7 +224,7 @@ void CircleTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const Q
if (ok) diameterFromInput = true; if (ok) diameterFromInput = true;
} }
QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), plane);
QVector3D edgePos; QVector3D edgePos;
double diameter; double diameter;
@@ -235,17 +232,15 @@ void CircleTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const Q
diameter = inputDiameter; diameter = inputDiameter;
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);
}
} }
edgePos = centerPos + mouseDir.normalized() * (diameter / 2.0); edgePos = centerPos + mouseDir.normalized() * (diameter / 2.0);
} else { } else {
edgePos = mousePos; edgePos = mousePos;
if (m_viewport->isSnappingOrigin()) { if (m_viewport->isSnappingOrigin()) {
edgePos.setX(0); edgePos.setY(0); edgePos.setZ(0); const auto& origin = plane.Location();
edgePos.setX(origin.X()); edgePos.setY(origin.Y()); edgePos.setZ(origin.Z());
} else if (m_viewport->isSnappingVertex()) { } else if (m_viewport->isSnappingVertex()) {
edgePos.setX(m_viewport->snapVertex().X()); edgePos.setY(m_viewport->snapVertex().Y()); edgePos.setZ(m_viewport->snapVertex().Z()); edgePos.setX(m_viewport->snapVertex().X()); edgePos.setY(m_viewport->snapVertex().Y()); edgePos.setZ(m_viewport->snapVertex().Z());
} }
@@ -271,4 +266,3 @@ void CircleTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const Q
painter.drawText(textRect, Qt::AlignCenter, diameterText); painter.drawText(textRect, Qt::AlignCenter, diameterText);
} }
} }
}
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+241 -236
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
@@ -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);
gp_Pnt worldPos(worldPosQ.x(), worldPosQ.y(), worldPosQ.z());
if (m_viewport->isSnappingHorizontal() || m_viewport->isSnappingVertical()) {
gp_Pnt2d worldPos2d(gp_Vec(plane.Location(), worldPos).Dot(plane.XDirection()), gp_Vec(plane.Location(), worldPos).Dot(plane.YDirection()));
gp_Pnt2d firstPoint2d(gp_Vec(plane.Location(), m_firstLinePoint).Dot(plane.XDirection()), gp_Vec(plane.Location(), m_firstLinePoint).Dot(plane.YDirection()));
if (m_viewport->isSnappingHorizontal()) { if (m_viewport->isSnappingHorizontal()) {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setY(m_firstLinePoint.Y()); worldPos2d.SetY(firstPoint2d.Y());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos.setZ(m_firstLinePoint.Z()); } else { // vertical
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) worldPos.setZ(m_firstLinePoint.Z()); worldPos2d.SetX(firstPoint2d.X());
} else if (m_viewport->isSnappingVertical()) {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setX(m_firstLinePoint.X());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos.setX(m_firstLinePoint.X());
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) worldPos.setY(m_firstLinePoint.Y());
} }
p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z()); worldPos = ElCLib::To3d(plane, worldPos2d);
}
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) {
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+143 -179
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
@@ -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,10 +176,14 @@ void RectangleTool::finalizeCreation()
void RectangleTool::paintGL() void RectangleTool::paintGL()
{ {
if (m_isDefining) { if (!m_isDefining) return;
auto currentPlaneOpt = m_viewport->currentPlane();
if (!currentPlaneOpt) return;
const auto& plane = currentPlaneOpt.value();
QVector<GLfloat> vertices; QVector<GLfloat> vertices;
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();
@@ -206,82 +202,70 @@ void RectangleTool::paintGL()
if (ok) heightFromInput = true; if (ok) heightFromInput = true;
} }
QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); QVector3D mousePosQ = m_viewport->unproject(m_viewport->currentMousePos(), plane);
gp_Pnt mousePos(mousePosQ.x(), mousePosQ.y(), mousePosQ.z());
if (widthFromInput || heightFromInput) { if (widthFromInput || heightFromInput) {
QVector3D mouseDir = mousePos - startPos; gp_Pnt2d startPos2d(gp_Vec(plane.Location(), startPos).Dot(plane.XDirection()), gp_Vec(plane.Location(), startPos).Dot(plane.YDirection()));
double current_w, current_h; 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) {
current_w = qAbs(mouseDir.x()); double current_w = qAbs(mousePos2d.X() - startPos2d.X());
current_h = qAbs(mouseDir.y()); double current_h = qAbs(mousePos2d.Y() - startPos2d.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_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 = mousePos; worldPosQ = mousePosQ;
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.setX(m_viewport->snapVertex().X()); worldPos.setY(m_viewport->snapVertex().Y()); worldPos.setZ(m_viewport->snapVertex().Z()); worldPosQ.setX(m_viewport->snapVertex().X()); worldPosQ.setY(m_viewport->snapVertex().Y()); worldPosQ.setZ(m_viewport->snapVertex().Z());
} }
} }
QVector3D p1 = startPos; gp_Pnt p1_3d = startPos;
QVector3D p2, p3, p4; gp_Pnt p3_3d(worldPosQ.x(), worldPosQ.y(), worldPosQ.z());
p3 = worldPos; 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()));
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { gp_Pnt2d p2_2d(p3_2d.X(), p1_2d.Y());
p2.setX(p3.x()); p2.setY(p1.y()); p2.setZ(p1.z()); gp_Pnt2d p4_2d(p1_2d.X(), p3_2d.Y());
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(); gp_Pnt p2_3d = ElCLib::To3d(plane, p2_2d);
vertices << p2.x() << p2.y() << p2.z(); gp_Pnt p4_3d = ElCLib::To3d(plane, p4_2d);
vertices << p2.x() << p2.y() << p2.z();
vertices << p3.x() << p3.y() << p3.z(); vertices << p1_3d.X() << p1_3d.Y() << p1_3d.Z();
vertices << p3.x() << p3.y() << p3.z(); vertices << p2_3d.X() << p2_3d.Y() << p2_3d.Z();
vertices << p4.x() << p4.y() << p4.z(); vertices << p2_3d.X() << p2_3d.Y() << p2_3d.Z();
vertices << p4.x() << p4.y() << p4.z(); vertices << p3_3d.X() << p3_3d.Y() << p3_3d.Z();
vertices << p1.x() << p1.y() << p1.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->shaderProgram()->setUniformValue(m_viewport->colorLoc(), QVector4D(1.0f, 1.0f, 0.0f, 1.0f));
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, 8); 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();
QVector3D worldPosQ;
gp_Pnt p1_3d = 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();
@@ -300,77 +284,58 @@ void RectangleTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, cons
if (ok) heightFromInput = true; if (ok) heightFromInput = true;
} }
QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane()); QVector3D mousePosQ = m_viewport->unproject(m_viewport->currentMousePos(), plane);
gp_Pnt mousePos(mousePosQ.x(), mousePosQ.y(), mousePosQ.z());
if (widthFromInput || heightFromInput) { if (widthFromInput || heightFromInput) {
QVector3D mouseDir = mousePos - p1_3d; gp_Pnt2d startPos2d(gp_Vec(plane.Location(), p1_3d).Dot(plane.XDirection()), gp_Vec(plane.Location(), p1_3d).Dot(plane.YDirection()));
double current_w, current_h; 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) {
current_w = qAbs(mouseDir.x()); double current_w = qAbs(mousePos2d.X() - startPos2d.X());
current_h = qAbs(mouseDir.y()); double current_h = qAbs(mousePos2d.Y() - startPos2d.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_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 signX = (mousePos2d.X() >= startPos2d.X()) ? 1 : -1;
int signY = (mouseDir.y() >= 0) ? 1 : -1; int signY = (mousePos2d.Y() >= startPos2d.Y()) ? 1 : -1;
int signZ = (mouseDir.z() >= 0) ? 1 : -1;
worldPos = p1_3d; gp_Pnt2d endPos2d(startPos2d.X() + signX * rect_w, startPos2d.Y() + signY * rect_h);
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { gp_Pnt endPos3d = ElCLib::To3d(plane, endPos2d);
worldPos.setX(p1_3d.x() + signX * rect_w); worldPosQ = QVector3D(endPos3d.X(), endPos3d.Y(), endPos3d.Z());
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 { } else {
worldPos = mousePos; worldPosQ = mousePosQ;
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.setX(m_viewport->snapVertex().X()); worldPos.setY(m_viewport->snapVertex().Y()); worldPos.setZ(m_viewport->snapVertex().Z()); worldPosQ.setX(m_viewport->snapVertex().X()); worldPosQ.setY(m_viewport->snapVertex().Y()); worldPosQ.setZ(m_viewport->snapVertex().Z());
} }
} }
QVector3D p3_3d = worldPos; gp_Pnt p3_3d(worldPosQ.x(), worldPosQ.y(), worldPosQ.z());
QVector3D p2_3d, p4_3d; gp_Pnt p2_3d, p4_3d;
double w, h; 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);
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { double w = qAbs(p3_2d.X() - p1_2d.X());
p2_3d.setX(p3_3d.x()); p2_3d.setY(p1_3d.y()); p2_3d.setZ(p1_3d.z()); double h = qAbs(p3_2d.Y() - p1_2d.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); painter.setRenderHint(QPainter::Antialiasing);
QFontMetrics fm(painter.font()); 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 // Width dimension
QVector3D widthTextPos3D = (p1_3d + p2_3d) / 2.0f; QVector3D widthTextPos3D = (p1_q + p2_q) / 2.0f;
QVector3D screenPosW = m_viewport->project(widthTextPos3D, modelView, projection, m_viewport->rect()); QVector3D screenPosW = m_viewport->project(widthTextPos3D, modelView, projection, m_viewport->rect());
if (screenPosW.z() < 1.0f) { if (screenPosW.z() < 1.0f) {
QString widthText = widthFromInput ? widthInput : QString::number(w, 'f', 2); QString widthText = widthFromInput ? widthInput : QString::number(w, 'f', 2);
QRect textRect = fm.boundingRect(widthText + "__"); QRect textRect = fm.boundingRect(widthText + "__");
textRect.moveCenter(screenPosW.toPoint() + QPoint(0, (p3_3d.z() > p1_3d.z() || p3_3d.y() > p1_3d.y()) ? -15 : 15)); textRect.moveCenter(screenPosW.toPoint() + QPoint(0, (p3_2d.Y() > p1_2d.Y()) ? -15 : 15));
if (m_viewport->property("dimensionEditMode").toString() == "width") { if (m_viewport->property("dimensionEditMode").toString() == "width") {
painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(64, 128, 255)); painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(64, 128, 255));
} else { } else {
@@ -381,12 +346,12 @@ void RectangleTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, cons
} }
// Height dimension // Height dimension
QVector3D heightTextPos3D = (p2_3d + p3_3d) / 2.0f; QVector3D heightTextPos3D = (p2_q + p3_q) / 2.0f;
QVector3D screenPosH = m_viewport->project(heightTextPos3D, modelView, projection, m_viewport->rect()); QVector3D screenPosH = m_viewport->project(heightTextPos3D, modelView, projection, m_viewport->rect());
if (screenPosH.z() < 1.0f) { if (screenPosH.z() < 1.0f) {
QString heightText = heightFromInput ? heightInput : QString::number(h, 'f', 2); QString heightText = heightFromInput ? heightInput : QString::number(h, 'f', 2);
QRect textRect = fm.boundingRect(heightText + "__"); QRect textRect = fm.boundingRect(heightText + "__");
textRect.moveCenter(screenPosH.toPoint() + QPoint((p3_3d.x() > p1_3d.x()) ? 15 : -15, 0)); textRect.moveCenter(screenPosH.toPoint() + QPoint((p3_2d.X() > p1_2d.X()) ? 15 : -15, 0));
if (m_viewport->property("dimensionEditMode").toString() == "height") { if (m_viewport->property("dimensionEditMode").toString() == "height") {
painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(64, 128, 255)); painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(64, 128, 255));
} else { } else {
@@ -396,4 +361,3 @@ void RectangleTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, cons
painter.drawText(textRect, Qt::AlignCenter, heightText); painter.drawText(textRect, Qt::AlignCenter, heightText);
} }
} }
}
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+67 -16
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
@@ -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) {
+6 -10
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
@@ -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;
}; };
+48 -43
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
@@ -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();
vertices << -axisLength << 0 << 0 << axisLength << 0 << 0; QVector3D p1 = originVec - axisLength * xDirVec;
QVector3D p2 = originVec + axisLength * xDirVec;
vertices << p1.x() << p1.y() << p1.z() << p2.x() << p2.y() << p2.z();
shaderProgram->setUniformValue(colorLoc, QVector4D(1.0f, 0.0f, 0.0f, 1.0f)); shaderProgram->setUniformValue(colorLoc, QVector4D(1.0f, 0.0f, 0.0f, 1.0f));
m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat)); m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
glDrawArrays(GL_LINES, 0, 2); glDrawArrays(GL_LINES, 0, 2);
}
// Y Axis (Green) // Y Axis (Green)
if (plane == XY || plane == YZ) {
vertices.clear(); vertices.clear();
vertices << 0 << -axisLength << 0 << 0 << axisLength << 0; QVector3D p3 = originVec - axisLength * yDirVec;
QVector3D p4 = originVec + axisLength * yDirVec;
vertices << p3.x() << p3.y() << p3.z() << p4.x() << p4.y() << p4.z();
shaderProgram->setUniformValue(colorLoc, QVector4D(0.0f, 1.0f, 0.0f, 1.0f)); shaderProgram->setUniformValue(colorLoc, QVector4D(0.0f, 1.0f, 0.0f, 1.0f));
m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat)); m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
glDrawArrays(GL_LINES, 0, 2); 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
}
} }
+6 -11
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
@@ -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;
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+63 -91
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
@@ -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();
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
+89 -81
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
@@ -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,9 +239,11 @@ 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) {
m_camera->startRotation(unproject(event->pos(), m_currentPlane.value()));
update(); update();
} }
}
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
if (m_viewCube->handleMousePress(event->pos(), width(), height())) { if (m_viewCube->handleMousePress(event->pos(), width(), height())) {
@@ -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,9 +306,11 @@ 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) {
QVector3D worldPos = unproject(event->position().toPoint(), m_currentPlane.value());
m_camera->wheelEvent(event, worldPos); 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;
} }
+10 -15
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE
@@ -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;
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3, see LICENSE.txt // License: GPLv3 (or later)
// Language: C++17 // Language: C++17
// Notes: // Notes:
// - use a right-handed, Z-up coordinate system to match Open CASCADE // - use a right-handed, Z-up coordinate system to match Open CASCADE