Compare commits

2 Commits

Author SHA1 Message Date
tanner 953b692f7d Add file headers 2026-02-19 10:59:15 -07:00
tanner 95dfacd994 Add GPLv3 license 2026-02-19 10:54:39 -07:00
41 changed files with 978 additions and 997 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 libfontconfig1-dev $ sudo apt install cmake qt6-base-dev qt6-svg-dev libtbb-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 (or later). Please see the `LICENSE.txt` file for details. This program is free and open-source software licensed under the GNU GPLv3. 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.
+17 -45
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3 (or later) // License: GPLv3, see LICENSE.txt
// 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,16 +13,6 @@
#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>
@@ -127,12 +117,26 @@ void ApplicationController::beginSketchCreation()
emit planeSelectionModeStarted(); emit planeSelectionModeStarted();
} }
void ApplicationController::onPlaneSelected(const gp_Ax2& plane) void ApplicationController::onPlaneSelected(ViewportWidget::SketchPlane plane)
{ {
auto feature = new SketchFeature("Sketch"); auto feature = new SketchFeature("Sketch");
m_activeSketch = feature; m_activeSketch = feature;
feature->setPlane(plane); switch (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);
@@ -142,10 +146,6 @@ 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,27 +153,6 @@ 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());
}
} }
} }
@@ -181,13 +160,6 @@ 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 (or later) // License: GPLv3, see LICENSE.txt
// 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(const gp_Ax2& plane); void onPlaneSelected(ViewportWidget::SketchPlane plane);
void endSketch(); void endSketch();
signals: signals:
void planeSelectionModeStarted(); void planeSelectionModeStarted();
void sketchModeStarted(const gp_Ax2& plane); void sketchModeStarted(ViewportWidget::SketchPlane plane);
void sketchModeEnded(); void sketchModeEnded();
void currentFileChanged(const QString& path); void currentFileChanged(const QString& path);
void activeToolChanged(ToolType tool); void activeToolChanged(ToolType tool);
+20 -24
View File
@@ -1,13 +1,12 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3 (or later) // License: GPLv3, see LICENSE.txt
// 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 <gp_Ax2.hxx> #include "ViewportWidget.h"
#include <gp_Dir.hxx>
#include <QApplication> #include <QApplication>
#include <QWheelEvent> #include <QWheelEvent>
#include <QPropertyAnimation> #include <QPropertyAnimation>
@@ -203,28 +202,25 @@ void Camera::restoreState()
setZoom(m_savedZoom); setZoom(m_savedZoom);
} }
void Camera::animateToPlaneView(const gp_Ax2& plane) void Camera::animateToPlaneView(int plane)
{ {
const auto& normal = plane.Direction(); float targetXRot = xRotation();
QVector3D n(normal.X(), normal.Y(), normal.Z()); float targetYRot = yRotation();
QVector3D d; switch (static_cast<ViewportWidget::SketchPlane>(plane)) {
case ViewportWidget::SketchPlane::XY: // Top view
// This logic preserves the quirky view directions of the original implementation. targetXRot = 90 * 16;
// For XZ-like planes (normal is mostly along Y), the view is aligned WITH the plane normal. targetYRot = 0;
// For other planes, it's aligned AGAINST the normal. break;
if (qAbs(n.y()) > 0.99) { case ViewportWidget::SketchPlane::XZ: // Front view
d = n; targetXRot = 0;
} else { targetYRot = 0;
d = -n; break;
} case ViewportWidget::SketchPlane::YZ: // Right view
targetXRot = 0;
float targetXRot = qRadiansToDegrees(asin(-d.z())) * 16.0f; targetYRot = -90 * 16;
float targetYRot; break;
case ViewportWidget::SketchPlane::NONE:
if (qAbs(d.z()) > 0.9999) { // Top/bottom-like view, Y rotation is arbitrary break;
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);
+2 -4
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3 (or later) // License: GPLv3, see LICENSE.txt
// 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,8 +14,6 @@
#include <QMouseEvent> #include <QMouseEvent>
#include <QWheelEvent> #include <QWheelEvent>
#include <gp_Ax2.hxx>
class Camera : public QObject class Camera : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -48,7 +46,7 @@ public:
void saveState(); void saveState();
void restoreState(); void restoreState();
void animateToPlaneView(const gp_Ax2& plane); void animateToPlaneView(int plane);
void animateRestoreState(); void animateRestoreState();
void animateToHomeView(); void animateToHomeView();
+132 -126
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3 (or later) // License: GPLv3, see LICENSE.txt
// 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,10 +15,6 @@
#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)
@@ -39,18 +35,14 @@ 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 = plane.Location(); p.SetCoord(0, 0, 0);
} 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(), plane); QVector3D worldPos = m_viewport->unproject(event->pos(), m_viewport->currentPlane());
p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z()); p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z());
} }
m_centerPoint = p; m_centerPoint = p;
@@ -78,22 +70,24 @@ void CircleTool::mousePressEvent(QMouseEvent *event)
} }
if (diameterFromInput) { if (diameterFromInput) {
QVector3D mousePos = m_viewport->unproject(event->pos(), plane); QVector3D mousePos = m_viewport->unproject(event->pos(), m_viewport->currentPlane());
QVector3D mouseDir = mousePos - centerPos; QVector3D mouseDir = mousePos - centerPos;
if (mouseDir.lengthSquared() < 1e-9) { if (mouseDir.lengthSquared() < 1e-9) {
const auto& xDir = plane.XDirection(); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
mouseDir = QVector3D(xDir.X(), xDir.Y(), xDir.Z()); mouseDir = QVector3D(1, 0, 0);
} 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()) {
const auto& origin = plane.Location(); worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0);
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(), plane); worldPos = m_viewport->unproject(event->pos(), m_viewport->currentPlane());
} }
} }
p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z()); p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z());
@@ -109,10 +103,6 @@ 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());
@@ -127,16 +117,19 @@ void CircleTool::finalizeCreation()
} }
if (diameterFromInput) { if (diameterFromInput) {
QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), plane); QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
QVector3D mouseDir = mousePos - centerPos; QVector3D mouseDir = mousePos - centerPos;
if (mouseDir.lengthSquared() < 1e-9) { if (mouseDir.lengthSquared() < 1e-9) {
const auto& xDir = plane.XDirection(); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
mouseDir = QVector3D(xDir.X(), xDir.Y(), xDir.Z()); mouseDir = QVector3D(1, 0, 0);
} 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(), plane); worldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
} }
gp_Pnt p; gp_Pnt p;
@@ -148,121 +141,134 @@ void CircleTool::finalizeCreation()
void CircleTool::paintGL() void CircleTool::paintGL()
{ {
auto currentPlaneOpt = m_viewport->currentPlane(); if (m_isDefining) {
if (!m_isDefining || !currentPlaneOpt) return; QVector<GLfloat> vertices;
const auto& plane = currentPlaneOpt.value(); QVector3D worldPos;
QVector3D centerPos(m_centerPoint.X(), m_centerPoint.Y(), m_centerPoint.Z());
QVector<GLfloat> vertices; QString diameterInput = m_viewport->property("diameterInput").toString();
QVector3D worldPos; bool diameterFromInput = false;
QVector3D centerPos(m_centerPoint.X(), m_centerPoint.Y(), m_centerPoint.Z()); double inputDiameter = 0;
QString diameterInput = m_viewport->property("diameterInput").toString(); if (!diameterInput.isEmpty()) {
bool diameterFromInput = false; bool ok;
double inputDiameter = 0; inputDiameter = diameterInput.toDouble(&ok);
if (ok) diameterFromInput = true;
if (!diameterInput.isEmpty()) {
bool ok;
inputDiameter = diameterInput.toDouble(&ok);
if (ok) diameterFromInput = true;
}
QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), plane);
double radius;
if (diameterFromInput) {
radius = inputDiameter / 2.0;
} else {
worldPos = mousePos;
if (m_viewport->isSnappingOrigin()) {
const auto& origin = plane.Location();
worldPos.setX(origin.X()); worldPos.setY(origin.Y()); worldPos.setZ(origin.Z());
} else if (m_viewport->isSnappingVertex()) {
worldPos.setX(m_viewport->snapVertex().X()); worldPos.setY(m_viewport->snapVertex().Y()); worldPos.setZ(m_viewport->snapVertex().Z());
} }
radius = (worldPos - centerPos).length();
QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
double radius;
if (diameterFromInput) {
radius = inputDiameter / 2.0;
} else {
worldPos = mousePos;
if (m_viewport->isSnappingOrigin()) {
worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0);
} else if (m_viewport->isSnappingVertex()) {
worldPos.setX(m_viewport->snapVertex().X()); worldPos.setY(m_viewport->snapVertex().Y()); worldPos.setZ(m_viewport->snapVertex().Z());
}
radius = (worldPos - centerPos).length();
}
const int segments = 64;
for (int i = 0; i < segments; ++i) {
double angle1 = i * 2.0 * M_PI / segments;
double angle2 = (i + 1) * 2.0 * M_PI / segments;
QVector3D p1, p2;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
p1.setX(centerPos.x() + radius * qCos(angle1));
p1.setY(centerPos.y() + radius * qSin(angle1));
p1.setZ(centerPos.z());
p2.setX(centerPos.x() + radius * qCos(angle2));
p2.setY(centerPos.y() + radius * qSin(angle2));
p2.setZ(centerPos.z());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
p1.setX(centerPos.x() + radius * qCos(angle1));
p1.setY(centerPos.y());
p1.setZ(centerPos.z() + radius * qSin(angle1));
p2.setX(centerPos.x() + radius * qCos(angle2));
p2.setY(centerPos.y());
p2.setZ(centerPos.z() + radius * qSin(angle2));
} else { // YZ
p1.setX(centerPos.x());
p1.setY(centerPos.y() + radius * qCos(angle1));
p1.setZ(centerPos.z() + radius * qSin(angle1));
p2.setX(centerPos.x());
p2.setY(centerPos.y() + radius * qCos(angle2));
p2.setZ(centerPos.z() + radius * qSin(angle2));
}
vertices << p1.x() << p1.y() << p1.z();
vertices << p2.x() << p2.y() << p2.z();
}
m_viewport->shaderProgram()->setUniformValue(m_viewport->colorLoc(), QVector4D(1.0f, 1.0f, 0.0f, 1.0f));
m_viewport->vbo().bind();
m_viewport->vbo().allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
glDrawArrays(GL_LINES, 0, segments * 2);
} }
const int segments = 64;
const auto& xDir = plane.XDirection();
const auto& yDir = plane.YDirection();
QVector3D u_axis(xDir.X(), xDir.Y(), xDir.Z());
QVector3D v_axis(yDir.X(), yDir.Y(), yDir.Z());
for (int i = 0; i < segments; ++i) {
double angle1 = i * 2.0 * M_PI / segments;
double angle2 = (i + 1) * 2.0 * M_PI / segments;
QVector3D p1 = centerPos + radius * (qCos(angle1) * u_axis + qSin(angle1) * v_axis);
QVector3D p2 = centerPos + radius * (qCos(angle2) * u_axis + qSin(angle2) * v_axis);
vertices << p1.x() << p1.y() << p1.z();
vertices << p2.x() << p2.y() << p2.z();
}
m_viewport->shaderProgram()->setUniformValue(m_viewport->colorLoc(), QVector4D(1.0f, 1.0f, 0.0f, 1.0f));
m_viewport->vbo().bind();
m_viewport->vbo().allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
glDrawArrays(GL_LINES, 0, segments * 2);
} }
void CircleTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection) void CircleTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection)
{ {
auto currentPlaneOpt = m_viewport->currentPlane(); if (m_isDefining) {
if (!m_isDefining || !currentPlaneOpt) return; QVector3D worldPos;
const auto& plane = currentPlaneOpt.value(); QVector3D centerPos(m_centerPoint.X(), m_centerPoint.Y(), m_centerPoint.Z());
QVector3D worldPos; QString diameterInput = m_viewport->property("diameterInput").toString();
QVector3D centerPos(m_centerPoint.X(), m_centerPoint.Y(), m_centerPoint.Z()); bool diameterFromInput = false;
double inputDiameter = 0;
QString diameterInput = m_viewport->property("diameterInput").toString(); if (!diameterInput.isEmpty()) {
bool diameterFromInput = false; bool ok;
double inputDiameter = 0; inputDiameter = diameterInput.toDouble(&ok);
if (ok) diameterFromInput = true;
if (!diameterInput.isEmpty()) {
bool ok;
inputDiameter = diameterInput.toDouble(&ok);
if (ok) diameterFromInput = true;
}
QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), plane);
QVector3D edgePos;
double diameter;
if (diameterFromInput) {
diameter = inputDiameter;
QVector3D mouseDir = mousePos - centerPos;
if (mouseDir.lengthSquared() < 1e-9) {
const auto& xDir = plane.XDirection();
mouseDir = QVector3D(xDir.X(), xDir.Y(), xDir.Z());
} }
edgePos = centerPos + mouseDir.normalized() * (diameter / 2.0);
} else {
edgePos = mousePos;
if (m_viewport->isSnappingOrigin()) {
const auto& origin = plane.Location();
edgePos.setX(origin.X()); edgePos.setY(origin.Y()); edgePos.setZ(origin.Z());
} else if (m_viewport->isSnappingVertex()) {
edgePos.setX(m_viewport->snapVertex().X()); edgePos.setY(m_viewport->snapVertex().Y()); edgePos.setZ(m_viewport->snapVertex().Z());
}
diameter = (edgePos - centerPos).length() * 2.0;
}
painter.setRenderHint(QPainter::Antialiasing); QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
QFontMetrics fm(painter.font()); QVector3D edgePos;
double diameter;
// Diameter dimension if (diameterFromInput) {
QVector3D diameterTextPos3D = (centerPos + edgePos) / 2.0f; diameter = inputDiameter;
QVector3D screenPosD = m_viewport->project(diameterTextPos3D, modelView, projection, m_viewport->rect()); QVector3D mouseDir = mousePos - centerPos;
if (screenPosD.z() < 1.0f) { if (mouseDir.lengthSquared() < 1e-9) {
QString diameterText = diameterFromInput ? diameterInput : QString::number(diameter, 'f', 2); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
QRect textRect = fm.boundingRect(diameterText + "__"); mouseDir = QVector3D(1, 0, 0);
textRect.moveCenter(screenPosD.toPoint()); } else { // YZ
if (m_viewport->property("dimensionEditMode").toString() == "diameter") { mouseDir = QVector3D(0, 1, 0);
painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(64, 128, 255)); }
}
edgePos = centerPos + mouseDir.normalized() * (diameter / 2.0);
} else { } else {
painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(50, 50, 50)); edgePos = mousePos;
if (m_viewport->isSnappingOrigin()) {
edgePos.setX(0); edgePos.setY(0); edgePos.setZ(0);
} else if (m_viewport->isSnappingVertex()) {
edgePos.setX(m_viewport->snapVertex().X()); edgePos.setY(m_viewport->snapVertex().Y()); edgePos.setZ(m_viewport->snapVertex().Z());
}
diameter = (edgePos - centerPos).length() * 2.0;
}
painter.setRenderHint(QPainter::Antialiasing);
QFontMetrics fm(painter.font());
// Diameter dimension
QVector3D diameterTextPos3D = (centerPos + edgePos) / 2.0f;
QVector3D screenPosD = m_viewport->project(diameterTextPos3D, modelView, projection, m_viewport->rect());
if (screenPosD.z() < 1.0f) {
QString diameterText = diameterFromInput ? diameterInput : QString::number(diameter, 'f', 2);
QRect textRect = fm.boundingRect(diameterText + "__");
textRect.moveCenter(screenPosD.toPoint());
if (m_viewport->property("dimensionEditMode").toString() == "diameter") {
painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(64, 128, 255));
} else {
painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(50, 50, 50));
}
painter.setPen(Qt::white);
painter.drawText(textRect, Qt::AlignCenter, diameterText);
} }
painter.setPen(Qt::white);
painter.drawText(textRect, Qt::AlignCenter, diameterText);
} }
} }
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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
+237 -242
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3 (or later) // License: GPLv3, see LICENSE.txt
// 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,13 +13,6 @@
#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)
@@ -41,10 +34,6 @@ 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();
@@ -75,23 +64,19 @@ 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 {
const auto& xDir = plane.XDirection(); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refDir = QVector3D(1, 0, 0);
refDir = QVector3D(xDir.X(), xDir.Y(), xDir.Z()); else refDir = QVector3D(0, 1, 0);
} }
QVector3D currentMouseWorldPos = m_viewport->unproject(event->pos(), plane); QVector3D currentMouseWorldPos = m_viewport->unproject(event->pos(), m_viewport->currentPlane());
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;
while (relativeMouseAngle > 180.0) relativeMouseAngle -= 360.0; while (relativeMouseAngle > 180.0) relativeMouseAngle -= 360.0;
@@ -106,9 +91,10 @@ void LineTool::mousePressEvent(QMouseEvent *event)
snappedAngle = -inputAngleDegrees; snappedAngle = -inputAngleDegrees;
} }
double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle); double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle);
gp_Dir2d finalDir2d(cos(finalAngleRad), sin(finalAngleRad)); QVector3D finalDir;
gp_Dir finalDir3d = ElCLib::To3d(plane, finalDir2d); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) finalDir = QVector3D(cos(finalAngleRad), sin(finalAngleRad), 0);
QVector3D finalDir(finalDir3d.X(), finalDir3d.Y(), finalDir3d.Z()); else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) finalDir = QVector3D(cos(finalAngleRad), 0, sin(finalAngleRad));
else finalDir = QVector3D(0, cos(finalAngleRad), sin(finalAngleRad));
double lineLength; double lineLength;
if (lengthFromInput) lineLength = inputLength; if (lengthFromInput) lineLength = inputLength;
else { else {
@@ -117,37 +103,34 @@ 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(), plane); QVector3D currentMouseWorldPos = m_viewport->unproject(event->pos(), m_viewport->currentPlane());
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 {
const auto& xDir = plane.XDirection(); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos = startPos + QVector3D(inputLength, 0, 0);
worldPos = startPos + inputLength * QVector3D(xDir.X(), xDir.Y(), xDir.Z()); else worldPos = startPos + QVector3D(0, inputLength, 0);
} }
} }
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 = plane.Location(); p.SetCoord(0, 0, 0);
} else if (m_viewport->isSnappingVertex()) { } else if (m_viewport->isSnappingVertex()) {
p = m_viewport->snapVertex(); p = m_viewport->snapVertex();
} else { } else {
QVector3D worldPosQ = m_viewport->unproject(event->pos(), plane); QVector3D worldPos = m_viewport->unproject(event->pos(), m_viewport->currentPlane());
gp_Pnt worldPos(worldPosQ.x(), worldPosQ.y(), worldPosQ.z()); if (m_viewport->isSnappingHorizontal()) {
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setY(m_firstLinePoint.Y());
if (m_viewport->isSnappingHorizontal() || m_viewport->isSnappingVertical()) { else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos.setZ(m_firstLinePoint.Z());
gp_Pnt2d worldPos2d(gp_Vec(plane.Location(), worldPos).Dot(plane.XDirection()), gp_Vec(plane.Location(), worldPos).Dot(plane.YDirection())); else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) 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->isSnappingVertical()) {
if (m_viewport->isSnappingHorizontal()) { if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setX(m_firstLinePoint.X());
worldPos2d.SetY(firstPoint2d.Y()); else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) worldPos.setX(m_firstLinePoint.X());
} else { // vertical else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) worldPos.setY(m_firstLinePoint.Y());
worldPos2d.SetX(firstPoint2d.X());
}
worldPos = ElCLib::To3d(plane, worldPos2d);
} }
p = worldPos; p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z());
} }
} }
@@ -174,27 +157,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 worldPosQ = m_viewport->unproject(m_viewport->currentMousePos(), plane); QVector3D worldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
gp_Pnt worldPos(worldPosQ.x(), worldPosQ.y(), worldPosQ.z()); QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
gp_Pnt startPos = m_firstLinePoint; QVector3D delta = worldPos - startPos;
gp_Pnt2d worldPos2d(gp_Vec(plane.Location(), worldPos).Dot(plane.XDirection()), gp_Vec(plane.Location(), worldPos).Dot(plane.YDirection())); if (delta.length() > 1e-6) {
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 = atan2(delta.Y(), delta.X()); double angle = 0;
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);
@@ -211,10 +194,6 @@ 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
@@ -241,23 +220,19 @@ 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 {
const auto& xDir = plane.XDirection(); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refDir = QVector3D(1, 0, 0);
refDir = QVector3D(xDir.X(), xDir.Y(), xDir.Z()); else refDir = QVector3D(0, 1, 0);
} }
QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), plane); QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
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;
while (relativeMouseAngle > 180.0) relativeMouseAngle -= 360.0; while (relativeMouseAngle > 180.0) relativeMouseAngle -= 360.0;
@@ -272,9 +247,10 @@ void LineTool::finalizeCreation()
snappedAngle = -inputAngleDegrees; snappedAngle = -inputAngleDegrees;
} }
double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle); double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle);
gp_Dir2d finalDir2d(cos(finalAngleRad), sin(finalAngleRad)); QVector3D finalDir;
gp_Dir finalDir3d = ElCLib::To3d(plane, finalDir2d); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) finalDir = QVector3D(cos(finalAngleRad), sin(finalAngleRad), 0);
QVector3D finalDir(finalDir3d.X(), finalDir3d.Y(), finalDir3d.Z()); else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) finalDir = QVector3D(cos(finalAngleRad), 0, sin(finalAngleRad));
else finalDir = QVector3D(0, cos(finalAngleRad), sin(finalAngleRad));
double lineLength; double lineLength;
if (lengthFromInput) lineLength = inputLength; if (lengthFromInput) lineLength = inputLength;
else { else {
@@ -283,17 +259,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(), plane); QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
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 {
const auto& xDir = plane.XDirection(); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) 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(), plane); worldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
} }
gp_Pnt p; gp_Pnt p;
@@ -313,10 +289,6 @@ 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());
@@ -344,24 +316,26 @@ 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 {
const auto& xDir = plane.XDirection(); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
refDir = QVector3D(xDir.X(), xDir.Y(), xDir.Z()); refDir = QVector3D(1, 0, 0);
} else { // YZ
refDir = QVector3D(0, 1, 0);
}
} }
QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), plane); QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
QVector3D mouseVec = currentMouseWorldPos - startPos; QVector3D mouseVec = currentMouseWorldPos - startPos;
gp_Pnt startPnt(startPos.x(), startPos.y(), startPos.z()); // Quadrant snapping
gp_Pnt mousePnt(currentMouseWorldPos.x(), currentMouseWorldPos.y(), currentMouseWorldPos.z()); double mouseAngle;
gp_Dir refDirGp(refDir.x(), refDir.y(), refDir.z()); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVec.y(), mouseVec.x()));
else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.x()));
else mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.y()));
gp_Pnt2d startPnt2d(gp_Vec(plane.Location(), startPnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), startPnt).Dot(plane.YDirection())); double refAngle;
gp_Pnt2d mousePnt2d(gp_Vec(plane.Location(), mousePnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), mousePnt).Dot(plane.YDirection())); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) refAngle = qRadiansToDegrees(atan2(refDir.y(), refDir.x()));
gp_Dir2d refDir2d(refDirGp.Dot(plane.XDirection()), refDirGp.Dot(plane.YDirection())); else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.x()));
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;
@@ -379,9 +353,10 @@ void LineTool::paintGL()
} }
double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle); double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle);
gp_Dir2d finalDir2d(cos(finalAngleRad), sin(finalAngleRad)); QVector3D finalDir;
gp_Dir finalDir3d = ElCLib::To3d(plane, finalDir2d); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) finalDir = QVector3D(cos(finalAngleRad), sin(finalAngleRad), 0);
QVector3D finalDir(finalDir3d.X(), finalDir3d.Y(), finalDir3d.Z()); else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) finalDir = QVector3D(cos(finalAngleRad), 0, sin(finalAngleRad));
else finalDir = QVector3D(0, cos(finalAngleRad), sin(finalAngleRad));
double lineLength; double lineLength;
if (lengthFromInput) { if (lengthFromInput) {
@@ -393,34 +368,33 @@ 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(), plane); QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
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 {
const auto& xDir = plane.XDirection(); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
worldPos = startPos + inputLength * QVector3D(xDir.X(), xDir.Y(), xDir.Z()); worldPos = startPos + QVector3D(inputLength, 0, 0);
} else {
worldPos = startPos + QVector3D(0, inputLength, 0);
}
} }
} else { } else {
worldPos = m_viewport->unproject(m_viewport->currentMousePos(), plane); worldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
gp_Pnt worldPosPnt(worldPos.x(), worldPos.y(), worldPos.z());
if (m_viewport->isSnappingOrigin()) { if (m_viewport->isSnappingOrigin()) {
worldPosPnt = plane.Location(); worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0);
} else if (m_viewport->isSnappingVertex()) { } else if (m_viewport->isSnappingVertex()) {
worldPosPnt = m_viewport->snapVertex(); worldPos.setX(m_viewport->snapVertex().X()); worldPos.setY(m_viewport->snapVertex().Y()); worldPos.setZ(m_viewport->snapVertex().Z());
} else if (m_viewport->isSnappingHorizontal() || m_viewport->isSnappingVertical()) { } else if (m_viewport->isSnappingHorizontal()) {
gp_Pnt2d worldPos2d(gp_Vec(plane.Location(), worldPosPnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), worldPosPnt).Dot(plane.YDirection())); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setY(m_firstLinePoint.Y());
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::XZ) worldPos.setZ(m_firstLinePoint.Z());
if (m_viewport->isSnappingHorizontal()) { else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) worldPos.setZ(m_firstLinePoint.Z());
worldPos2d.SetY(firstPoint2d.Y()); } else if (m_viewport->isSnappingVertical()) {
} else { // vertical if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setX(m_firstLinePoint.X());
worldPos2d.SetX(firstPoint2d.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());
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();
@@ -442,25 +416,23 @@ 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 {
const auto& xDir = plane.XDirection(); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refDir = QVector3D(1, 0, 0);
refDir = QVector3D(xDir.X(), xDir.Y(), xDir.Z()); else refDir = QVector3D(0, 1, 0);
} }
if (angleFromInput) { if (angleFromInput) {
QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), plane); QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
QVector3D mouseVec = currentMouseWorldPos - startPos; QVector3D mouseVec = currentMouseWorldPos - startPos;
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()));
gp_Pnt2d startPnt2d(gp_Vec(plane.Location(), startPnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), startPnt).Dot(plane.YDirection())); double refAngleForQuadrant;
gp_Pnt2d mousePnt2d(gp_Vec(plane.Location(), mousePnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), mousePnt).Dot(plane.YDirection())); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.y(), refDir.x()));
gp_Dir2d refDir2d(refDirGp.Dot(plane.XDirection()), refDirGp.Dot(plane.YDirection())); else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.z(), refDir.x()));
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;
@@ -475,14 +447,16 @@ void LineTool::paintGL()
} }
} }
gp_Dir refDirGp(refDir.x(), refDir.y(), refDir.z()); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
gp_Dir lineDirGp(lineVec.x(), lineVec.y(), lineVec.z()); refAngle = atan2(refDir.y(), refDir.x());
lineAngle = atan2(lineVec.y(), lineVec.x());
gp_Dir2d refDir2d(refDirGp.Dot(plane.XDirection()), refDirGp.Dot(plane.YDirection())); } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
gp_Dir2d lineDir2d(lineDirGp.Dot(plane.XDirection()), lineDirGp.Dot(plane.YDirection())); refAngle = atan2(refDir.z(), refDir.x());
lineAngle = atan2(lineVec.z(), lineVec.x());
refAngle = atan2(refDir2d.Y(), refDir2d.X()); } else { // YZ
lineAngle = atan2(lineDir2d.Y(), lineDir2d.X()); refAngle = atan2(refDir.z(), refDir.y());
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;
@@ -492,11 +466,14 @@ void LineTool::paintGL()
vertices.clear(); vertices.clear();
gp_Dir lineDirGp(lineVec.x(), lineVec.y(), lineVec.z()); QVector3D perpVec;
gp_Dir2d lineDir2d(lineDirGp.Dot(plane.XDirection()), lineDirGp.Dot(plane.YDirection())); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
gp_Dir2d perpDir2d(-lineDir2d.Y(), lineDir2d.X()); perpVec = QVector3D(-lineVec.y(), lineVec.x(), 0).normalized();
gp_Dir perpDir3d = ElCLib::To3d(plane, perpDir2d); } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
QVector3D perpVec(perpDir3d.X(), perpDir3d.Y(), perpDir3d.Z()); 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;
@@ -543,11 +520,9 @@ 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;
const auto& xDir = plane.XDirection(); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) p = startPos + radius * QVector3D(cos(angle), sin(angle), 0);
const auto& yDir = plane.YDirection(); else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) p = startPos + radius * QVector3D(cos(angle), 0, sin(angle));
QVector3D u_axis(xDir.X(), xDir.Y(), xDir.Z()); else p = startPos + radius * QVector3D(0, cos(angle), sin(angle));
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);
@@ -565,13 +540,17 @@ 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;
radialDir_end = cos(endAngle) * u_axis + sin(endAngle) * v_axis; if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
tangentDir_end = -sin(endAngle) * u_axis + cos(endAngle) * v_axis; radialDir_end = QVector3D(cos(endAngle), sin(endAngle), 0);
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;
@@ -582,8 +561,16 @@ 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;
radialDir_start = cos(startAngle) * u_axis + sin(startAngle) * v_axis; if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
tangentDir_start = -sin(startAngle) * u_axis + cos(startAngle) * v_axis; radialDir_start = QVector3D(cos(startAngle), sin(startAngle), 0);
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;
@@ -602,21 +589,29 @@ 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()) {
p1 = midPoint - indicatorSize * v_axis + indicatorOffset * u_axis; if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
p2 = midPoint + indicatorSize * v_axis + indicatorOffset * u_axis; vertices << midPoint.x() - indicatorSize << midPoint.y() + indicatorOffset << midPoint.z();
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
p1 = midPoint - indicatorSize * u_axis + indicatorOffset * v_axis; if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
p2 = midPoint + indicatorSize * u_axis + indicatorOffset * v_axis; vertices << midPoint.x() + indicatorOffset << midPoint.y() - indicatorSize << midPoint.z();
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);
@@ -627,10 +622,6 @@ 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;
@@ -660,24 +651,25 @@ 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 {
const auto& xDir = plane.XDirection(); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
refDir = QVector3D(xDir.X(), xDir.Y(), xDir.Z()); refDir = QVector3D(1, 0, 0);
} else { // YZ
refDir = QVector3D(0, 1, 0);
}
} }
QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), plane); QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
QVector3D mouseVec = currentMouseWorldPos - startPos; QVector3D mouseVec = currentMouseWorldPos - startPos;
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()));
gp_Pnt2d startPnt2d(gp_Vec(plane.Location(), startPnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), startPnt).Dot(plane.YDirection())); double refAngle;
gp_Pnt2d mousePnt2d(gp_Vec(plane.Location(), mousePnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), mousePnt).Dot(plane.YDirection())); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) refAngle = qRadiansToDegrees(atan2(refDir.y(), refDir.x()));
gp_Dir2d refDir2d(refDirGp.Dot(plane.XDirection()), refDirGp.Dot(plane.YDirection())); else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.x()));
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;
@@ -695,9 +687,10 @@ void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMa
} }
double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle); double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle);
gp_Dir2d finalDir2d(cos(finalAngleRad), sin(finalAngleRad)); QVector3D finalDir;
gp_Dir finalDir3d = ElCLib::To3d(plane, finalDir2d); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) finalDir = QVector3D(cos(finalAngleRad), sin(finalAngleRad), 0);
QVector3D finalDir(finalDir3d.X(), finalDir3d.Y(), finalDir3d.Z()); else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) finalDir = QVector3D(cos(finalAngleRad), 0, sin(finalAngleRad));
else finalDir = QVector3D(0, cos(finalAngleRad), sin(finalAngleRad));
if (lengthFromInput) { if (lengthFromInput) {
lineLength = inputLength; lineLength = inputLength;
@@ -709,34 +702,33 @@ 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(), plane); QVector3D currentMouseWorldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
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 {
const auto& xDir = plane.XDirection(); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
worldPos = startPos + inputLength * QVector3D(xDir.X(), xDir.Y(), xDir.Z()); worldPos = startPos + QVector3D(inputLength, 0, 0);
} else {
worldPos = startPos + QVector3D(0, inputLength, 0);
}
} }
} else { } else {
worldPos = m_viewport->unproject(m_viewport->currentMousePos(), plane); worldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
gp_Pnt worldPosPnt(worldPos.x(), worldPos.y(), worldPos.z());
if (m_viewport->isSnappingOrigin()) { if (m_viewport->isSnappingOrigin()) {
worldPosPnt = plane.Location(); worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0);
} else if (m_viewport->isSnappingVertex()) { } else if (m_viewport->isSnappingVertex()) {
worldPosPnt = m_viewport->snapVertex(); worldPos.setX(m_viewport->snapVertex().X()); worldPos.setY(m_viewport->snapVertex().Y()); worldPos.setZ(m_viewport->snapVertex().Z());
} else if (m_viewport->isSnappingHorizontal() || m_viewport->isSnappingVertical()) { } else if (m_viewport->isSnappingHorizontal()) {
gp_Pnt2d worldPos2d(gp_Vec(plane.Location(), worldPosPnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), worldPosPnt).Dot(plane.YDirection())); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setY(m_firstLinePoint.Y());
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::XZ) worldPos.setZ(m_firstLinePoint.Z());
if (m_viewport->isSnappingHorizontal()) { else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) worldPos.setZ(m_firstLinePoint.Z());
worldPos2d.SetY(firstPoint2d.Y()); } else if (m_viewport->isSnappingVertical()) {
} else { // vertical if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) worldPos.setX(m_firstLinePoint.X());
worldPos2d.SetX(firstPoint2d.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());
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();
} }
@@ -747,26 +739,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 {
const auto& xDir = plane.XDirection(); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY || m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refDir = QVector3D(1, 0, 0);
refDir = QVector3D(xDir.X(), xDir.Y(), xDir.Z()); else refDir = QVector3D(0, 1, 0);
} }
QVector3D currentMouseWorldPosForText = m_viewport->unproject(m_viewport->currentMousePos(), plane); QVector3D currentMouseWorldPosForText = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
QVector3D mouseVecForText = currentMouseWorldPosForText - startPos; QVector3D mouseVecForText = currentMouseWorldPosForText - startPos;
if (angleFromInput) { if (angleFromInput) {
if (mouseVecForText.length() > 1e-6) { if (mouseVecForText.length() > 1e-6) {
gp_Pnt startPnt(startPos.x(), startPos.y(), startPos.z()); double mouseAngle;
gp_Pnt mousePnt(currentMouseWorldPosForText.x(), currentMouseWorldPosForText.y(), currentMouseWorldPosForText.z()); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVecForText.y(), mouseVecForText.x()));
gp_Dir refDirGp(refDir.x(), refDir.y(), refDir.z()); else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVecForText.z(), mouseVecForText.x()));
else mouseAngle = qRadiansToDegrees(atan2(mouseVecForText.z(), mouseVecForText.y()));
gp_Pnt2d startPnt2d(gp_Vec(plane.Location(), startPnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), startPnt).Dot(plane.YDirection())); double refAngleForQuadrant;
gp_Pnt2d mousePnt2d(gp_Vec(plane.Location(), mousePnt).Dot(plane.XDirection()), gp_Vec(plane.Location(), mousePnt).Dot(plane.YDirection())); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.y(), refDir.x()));
gp_Dir2d refDir2d(refDirGp.Dot(plane.XDirection()), refDirGp.Dot(plane.YDirection())); else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) refAngleForQuadrant = qRadiansToDegrees(atan2(refDir.z(), refDir.x()));
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;
@@ -782,23 +772,30 @@ void LineTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMa
} }
} }
gp_Dir refDirGp(refDir.x(), refDir.y(), refDir.z()); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
gp_Dir lineDirGp(lineVec.x(), lineVec.y(), lineVec.z()); refAngle = atan2(refDir.y(), refDir.x());
lineAngle = atan2(lineVec.y(), lineVec.x());
gp_Dir2d refDir2d(refDirGp.Dot(plane.XDirection()), refDirGp.Dot(plane.YDirection())); } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
gp_Dir2d lineDir2d(lineDirGp.Dot(plane.XDirection()), lineDirGp.Dot(plane.YDirection())); refAngle = atan2(refDir.z(), refDir.x());
lineAngle = atan2(lineVec.z(), lineVec.x());
refAngle = atan2(refDir2d.Y(), refDir2d.X()); } else { // YZ
lineAngle = atan2(lineDir2d.Y(), lineDir2d.X()); refAngle = atan2(refDir.z(), refDir.y());
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;
gp_Dir2d perpDir2d(-lineDir2d.Y(), lineDir2d.X()); QVector3D perpVec;
gp_Dir perpDir3d = ElCLib::To3d(plane, perpDir2d); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
QVector3D perpVec(perpDir3d.X(), perpDir3d.Y(), perpDir3d.Z()); perpVec = QVector3D(-lineVec.y(), lineVec.x(), 0).normalized();
} 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;
@@ -841,11 +838,9 @@ 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();
const auto& xDir = plane.XDirection(); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) textPos3DAngle = startPos + (radius + textOffset) * QVector3D(cos(midAngle), sin(midAngle), 0);
const auto& yDir = plane.YDirection(); else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) textPos3DAngle = startPos + (radius + textOffset) * QVector3D(cos(midAngle), 0, sin(midAngle));
QVector3D u_axis(xDir.X(), xDir.Y(), xDir.Z()); else textPos3DAngle = startPos + (radius + textOffset) * QVector3D(0, cos(midAngle), sin(midAngle));
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 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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
+261 -225
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3 (or later) // License: GPLv3, see LICENSE.txt
// 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,11 +15,6 @@
#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)
@@ -40,18 +35,14 @@ 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 = plane.Location(); p.SetCoord(0, 0, 0);
} 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(), plane); QVector3D worldPos = m_viewport->unproject(event->pos(), m_viewport->currentPlane());
p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z()); p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z());
} }
m_firstRectanglePoint = p; m_firstRectanglePoint = p;
@@ -60,8 +51,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 worldPosQ; QVector3D worldPos;
gp_Pnt startPos = m_firstRectanglePoint; QVector3D startPos(m_firstRectanglePoint.X(), m_firstRectanglePoint.Y(), m_firstRectanglePoint.Z());
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();
@@ -80,35 +71,45 @@ void RectangleTool::mousePressEvent(QMouseEvent *event)
} }
if (widthFromInput || heightFromInput) { if (widthFromInput || heightFromInput) {
QVector3D mousePosQ = m_viewport->unproject(event->pos(), plane); QVector3D mousePos = m_viewport->unproject(event->pos(), m_viewport->currentPlane());
gp_Pnt mousePos(mousePosQ.x(), mousePosQ.y(), mousePosQ.z()); QVector3D mouseDir = mousePos - startPos;
double current_w, current_h;
gp_Pnt2d startPos2d(gp_Vec(plane.Location(), startPos).Dot(plane.XDirection()), gp_Vec(plane.Location(), startPos).Dot(plane.YDirection())); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
gp_Pnt2d mousePos2d(gp_Vec(plane.Location(), mousePos).Dot(plane.XDirection()), gp_Vec(plane.Location(), mousePos).Dot(plane.YDirection())); current_w = qAbs(mouseDir.x());
current_h = qAbs(mouseDir.y());
double current_w = qAbs(mousePos2d.X() - startPos2d.X()); } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
double current_h = qAbs(mousePos2d.Y() - startPos2d.Y()); 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 = startPos;
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(startPos.x() + signX * rect_w);
worldPosQ = QVector3D(endPos3d.X(), endPos3d.Y(), endPos3d.Z()); worldPos.setY(startPos.y() + signY * rect_h);
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
worldPos.setX(startPos.x() + signX * rect_w);
worldPos.setZ(startPos.z() + signZ * rect_h);
} else { // YZ
worldPos.setY(startPos.y() + signY * rect_w);
worldPos.setZ(startPos.z() + signZ * rect_h);
}
} else { } else {
if (m_viewport->isSnappingOrigin()) { if (m_viewport->isSnappingOrigin()) {
const auto& origin = plane.Location(); worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0);
worldPosQ.setX(origin.X()); worldPosQ.setY(origin.Y()); worldPosQ.setZ(origin.Z());
} else if (m_viewport->isSnappingVertex()) { } else if (m_viewport->isSnappingVertex()) {
worldPosQ = 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 {
worldPosQ = m_viewport->unproject(event->pos(), plane); worldPos = m_viewport->unproject(event->pos(), m_viewport->currentPlane());
} }
} }
p.SetCoord(worldPosQ.x(), worldPosQ.y(), worldPosQ.z()); p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z());
emit m_viewport->rectangleAdded(m_firstRectanglePoint, p); emit m_viewport->rectangleAdded(m_firstRectanglePoint, p);
deactivate(); deactivate();
} }
@@ -121,12 +122,8 @@ void RectangleTool::mouseMoveEvent(QMouseEvent *event)
void RectangleTool::finalizeCreation() void RectangleTool::finalizeCreation()
{ {
auto currentPlaneOpt = m_viewport->currentPlane(); QVector3D worldPos;
if (!currentPlaneOpt) return; QVector3D startPos(m_firstRectanglePoint.X(), m_firstRectanglePoint.Y(), m_firstRectanglePoint.Z());
const auto& plane = currentPlaneOpt.value();
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();
@@ -145,30 +142,41 @@ void RectangleTool::finalizeCreation()
} }
if (widthFromInput || heightFromInput) { if (widthFromInput || heightFromInput) {
QVector3D mousePosQ = m_viewport->unproject(m_viewport->currentMousePos(), plane); QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
gp_Pnt mousePos(mousePosQ.x(), mousePosQ.y(), mousePosQ.z()); QVector3D mouseDir = mousePos - startPos;
double current_w, current_h;
gp_Pnt2d startPos2d(gp_Vec(plane.Location(), startPos).Dot(plane.XDirection()), gp_Vec(plane.Location(), startPos).Dot(plane.YDirection())); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
gp_Pnt2d mousePos2d(gp_Vec(plane.Location(), mousePos).Dot(plane.XDirection()), gp_Vec(plane.Location(), mousePos).Dot(plane.YDirection())); current_w = qAbs(mouseDir.x());
current_h = qAbs(mouseDir.y());
double current_w = qAbs(mousePos2d.X() - startPos2d.X()); } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
double current_h = qAbs(mousePos2d.Y() - startPos2d.Y()); 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 = startPos;
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(startPos.x() + signX * rect_w);
worldPosQ = QVector3D(endPos3d.X(), endPos3d.Y(), endPos3d.Z()); worldPos.setY(startPos.y() + signY * rect_h);
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
worldPos.setX(startPos.x() + signX * rect_w);
worldPos.setZ(startPos.z() + signZ * rect_h);
} else { // YZ
worldPos.setY(startPos.y() + signY * rect_w);
worldPos.setZ(startPos.z() + signZ * rect_h);
}
} else { } else {
worldPosQ = m_viewport->unproject(m_viewport->currentMousePos(), plane); worldPos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
} }
gp_Pnt p; gp_Pnt p;
p.SetCoord(worldPosQ.x(), worldPosQ.y(), worldPosQ.z()); p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z());
emit m_viewport->rectangleAdded(m_firstRectanglePoint, p); emit m_viewport->rectangleAdded(m_firstRectanglePoint, p);
deactivate(); deactivate();
@@ -176,188 +184,216 @@ void RectangleTool::finalizeCreation()
void RectangleTool::paintGL() void RectangleTool::paintGL()
{ {
if (!m_isDefining) return; if (m_isDefining) {
auto currentPlaneOpt = m_viewport->currentPlane(); QVector<GLfloat> vertices;
if (!currentPlaneOpt) return; QVector3D worldPos;
const auto& plane = currentPlaneOpt.value(); QVector3D startPos(m_firstRectanglePoint.X(), m_firstRectanglePoint.Y(), m_firstRectanglePoint.Z());
QVector<GLfloat> vertices; QString widthInput = m_viewport->property("widthInput").toString();
QVector3D worldPosQ; QString heightInput = m_viewport->property("heightInput").toString();
gp_Pnt startPos = m_firstRectanglePoint; bool widthFromInput = false;
bool heightFromInput = false;
double inputWidth = 0, inputHeight = 0;
QString widthInput = m_viewport->property("widthInput").toString(); if (!widthInput.isEmpty()) {
QString heightInput = m_viewport->property("heightInput").toString(); bool ok;
bool widthFromInput = false; inputWidth = widthInput.toDouble(&ok);
bool heightFromInput = false; if (ok) widthFromInput = true;
double inputWidth = 0, inputHeight = 0;
if (!widthInput.isEmpty()) {
bool ok;
inputWidth = widthInput.toDouble(&ok);
if (ok) widthFromInput = true;
}
if (!heightInput.isEmpty()) {
bool ok;
inputHeight = heightInput.toDouble(&ok);
if (ok) heightFromInput = true;
}
QVector3D mousePosQ = m_viewport->unproject(m_viewport->currentMousePos(), plane);
gp_Pnt mousePos(mousePosQ.x(), mousePosQ.y(), mousePosQ.z());
if (widthFromInput || heightFromInput) {
gp_Pnt2d startPos2d(gp_Vec(plane.Location(), startPos).Dot(plane.XDirection()), gp_Vec(plane.Location(), startPos).Dot(plane.YDirection()));
gp_Pnt2d mousePos2d(gp_Vec(plane.Location(), mousePos).Dot(plane.XDirection()), gp_Vec(plane.Location(), mousePos).Dot(plane.YDirection()));
double current_w = qAbs(mousePos2d.X() - startPos2d.X());
double current_h = qAbs(mousePos2d.Y() - startPos2d.Y());
double rect_w = widthFromInput ? inputWidth : current_w;
double rect_h = heightFromInput ? inputHeight : current_h;
int signX = (mousePos2d.X() >= startPos2d.X()) ? 1 : -1;
int signY = (mousePos2d.Y() >= startPos2d.Y()) ? 1 : -1;
gp_Pnt2d endPos2d(startPos2d.X() + signX * rect_w, startPos2d.Y() + signY * rect_h);
gp_Pnt endPos3d = ElCLib::To3d(plane, endPos2d);
worldPosQ = QVector3D(endPos3d.X(), endPos3d.Y(), endPos3d.Z());
} else {
worldPosQ = mousePosQ;
if (m_viewport->isSnappingOrigin()) {
const auto& origin = plane.Location();
worldPosQ.setX(origin.X()); worldPosQ.setY(origin.Y()); worldPosQ.setZ(origin.Z());
} else if (m_viewport->isSnappingVertex()) {
worldPosQ.setX(m_viewport->snapVertex().X()); worldPosQ.setY(m_viewport->snapVertex().Y()); worldPosQ.setZ(m_viewport->snapVertex().Z());
} }
if (!heightInput.isEmpty()) {
bool ok;
inputHeight = heightInput.toDouble(&ok);
if (ok) heightFromInput = true;
}
QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
if (widthFromInput || heightFromInput) {
QVector3D mouseDir = mousePos - startPos;
double current_w, current_h;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
current_w = qAbs(mouseDir.x());
current_h = qAbs(mouseDir.y());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
current_w = qAbs(mouseDir.x());
current_h = qAbs(mouseDir.z());
} else { // YZ
current_w = qAbs(mouseDir.y());
current_h = qAbs(mouseDir.z());
}
double rect_w = widthFromInput ? inputWidth : current_w;
double rect_h = heightFromInput ? inputHeight : current_h;
int signX = (mouseDir.x() >= 0) ? 1 : -1;
int signY = (mouseDir.y() >= 0) ? 1 : -1;
int signZ = (mouseDir.z() >= 0) ? 1 : -1;
worldPos = startPos;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
worldPos.setX(startPos.x() + signX * rect_w);
worldPos.setY(startPos.y() + signY * rect_h);
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
worldPos.setX(startPos.x() + signX * rect_w);
worldPos.setZ(startPos.z() + signZ * rect_h);
} else { // YZ
worldPos.setY(startPos.y() + signY * rect_w);
worldPos.setZ(startPos.z() + signZ * rect_h);
}
} else {
worldPos = mousePos;
if (m_viewport->isSnappingOrigin()) {
worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0);
} else if (m_viewport->isSnappingVertex()) {
worldPos.setX(m_viewport->snapVertex().X()); worldPos.setY(m_viewport->snapVertex().Y()); worldPos.setZ(m_viewport->snapVertex().Z());
}
}
QVector3D p1 = startPos;
QVector3D p2, p3, p4;
p3 = worldPos;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
p2.setX(p3.x()); p2.setY(p1.y()); p2.setZ(p1.z());
p4.setX(p1.x()); p4.setY(p3.y()); p4.setZ(p1.z());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
p2.setX(p3.x()); p2.setY(p1.y()); p2.setZ(p1.z());
p4.setX(p1.x()); p4.setY(p1.y()); p4.setZ(p3.z());
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::YZ) {
p2.setX(p1.x()); p2.setY(p3.y()); p2.setZ(p1.z());
p4.setX(p1.x()); p4.setY(p1.y()); p4.setZ(p3.z());
}
vertices << p1.x() << p1.y() << p1.z();
vertices << p2.x() << p2.y() << p2.z();
vertices << p2.x() << p2.y() << p2.z();
vertices << p3.x() << p3.y() << p3.z();
vertices << p3.x() << p3.y() << p3.z();
vertices << p4.x() << p4.y() << p4.z();
vertices << p4.x() << p4.y() << p4.z();
vertices << p1.x() << p1.y() << p1.z();
m_viewport->shaderProgram()->setUniformValue(m_viewport->colorLoc(), QVector4D(1.0f, 1.0f, 0.0f, 1.0f));
m_viewport->vbo().bind();
m_viewport->vbo().allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
glDrawArrays(GL_LINES, 0, 8);
} }
gp_Pnt p1_3d = startPos;
gp_Pnt p3_3d(worldPosQ.x(), worldPosQ.y(), worldPosQ.z());
gp_Pnt2d p1_2d(gp_Vec(plane.Location(), p1_3d).Dot(plane.XDirection()), gp_Vec(plane.Location(), p1_3d).Dot(plane.YDirection()));
gp_Pnt2d p3_2d(gp_Vec(plane.Location(), p3_3d).Dot(plane.XDirection()), gp_Vec(plane.Location(), p3_3d).Dot(plane.YDirection()));
gp_Pnt2d p2_2d(p3_2d.X(), p1_2d.Y());
gp_Pnt2d p4_2d(p1_2d.X(), p3_2d.Y());
gp_Pnt p2_3d = ElCLib::To3d(plane, p2_2d);
gp_Pnt p4_3d = ElCLib::To3d(plane, p4_2d);
vertices << p1_3d.X() << p1_3d.Y() << p1_3d.Z();
vertices << p2_3d.X() << p2_3d.Y() << p2_3d.Z();
vertices << p2_3d.X() << p2_3d.Y() << p2_3d.Z();
vertices << p3_3d.X() << p3_3d.Y() << p3_3d.Z();
vertices << p3_3d.X() << p3_3d.Y() << p3_3d.Z();
vertices << p4_3d.X() << p4_3d.Y() << p4_3d.Z();
vertices << p4_3d.X() << p4_3d.Y() << p4_3d.Z();
vertices << p1_3d.X() << p1_3d.Y() << p1_3d.Z();
m_viewport->shaderProgram()->setUniformValue(m_viewport->colorLoc(), QVector4D(1.0f, 1.0f, 0.0f, 1.0f));
m_viewport->vbo().bind();
m_viewport->vbo().allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
glDrawArrays(GL_LINES, 0, 8);
} }
void RectangleTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection) void RectangleTool::paint2D(QPainter& painter, const QMatrix4x4& modelView, const QMatrix4x4& projection)
{ {
if (!m_isDefining) return; if (m_isDefining) {
auto currentPlaneOpt = m_viewport->currentPlane(); QVector3D worldPos;
if (!currentPlaneOpt) return; QVector3D p1_3d(m_firstRectanglePoint.X(), m_firstRectanglePoint.Y(), m_firstRectanglePoint.Z());
const auto& plane = currentPlaneOpt.value();
QVector3D worldPosQ; QString widthInput = m_viewport->property("widthInput").toString();
gp_Pnt p1_3d = m_firstRectanglePoint; QString heightInput = m_viewport->property("heightInput").toString();
bool widthFromInput = false;
bool heightFromInput = false;
double inputWidth = 0, inputHeight = 0;
QString widthInput = m_viewport->property("widthInput").toString(); if (!widthInput.isEmpty()) {
QString heightInput = m_viewport->property("heightInput").toString(); bool ok;
bool widthFromInput = false; inputWidth = widthInput.toDouble(&ok);
bool heightFromInput = false; if (ok) widthFromInput = true;
double inputWidth = 0, inputHeight = 0; }
if (!heightInput.isEmpty()) {
if (!widthInput.isEmpty()) { bool ok;
bool ok; inputHeight = heightInput.toDouble(&ok);
inputWidth = widthInput.toDouble(&ok); if (ok) heightFromInput = true;
if (ok) widthFromInput = true;
}
if (!heightInput.isEmpty()) {
bool ok;
inputHeight = heightInput.toDouble(&ok);
if (ok) heightFromInput = true;
}
QVector3D mousePosQ = m_viewport->unproject(m_viewport->currentMousePos(), plane);
gp_Pnt mousePos(mousePosQ.x(), mousePosQ.y(), mousePosQ.z());
if (widthFromInput || heightFromInput) {
gp_Pnt2d startPos2d(gp_Vec(plane.Location(), p1_3d).Dot(plane.XDirection()), gp_Vec(plane.Location(), p1_3d).Dot(plane.YDirection()));
gp_Pnt2d mousePos2d(gp_Vec(plane.Location(), mousePos).Dot(plane.XDirection()), gp_Vec(plane.Location(), mousePos).Dot(plane.YDirection()));
double current_w = qAbs(mousePos2d.X() - startPos2d.X());
double current_h = qAbs(mousePos2d.Y() - startPos2d.Y());
double rect_w = widthFromInput ? inputWidth : current_w;
double rect_h = heightFromInput ? inputHeight : current_h;
int signX = (mousePos2d.X() >= startPos2d.X()) ? 1 : -1;
int signY = (mousePos2d.Y() >= startPos2d.Y()) ? 1 : -1;
gp_Pnt2d endPos2d(startPos2d.X() + signX * rect_w, startPos2d.Y() + signY * rect_h);
gp_Pnt endPos3d = ElCLib::To3d(plane, endPos2d);
worldPosQ = QVector3D(endPos3d.X(), endPos3d.Y(), endPos3d.Z());
} else {
worldPosQ = mousePosQ;
if (m_viewport->isSnappingOrigin()) {
const auto& origin = plane.Location();
worldPosQ.setX(origin.X()); worldPosQ.setY(origin.Y()); worldPosQ.setZ(origin.Z());
} else if (m_viewport->isSnappingVertex()) {
worldPosQ.setX(m_viewport->snapVertex().X()); worldPosQ.setY(m_viewport->snapVertex().Y()); worldPosQ.setZ(m_viewport->snapVertex().Z());
} }
}
gp_Pnt p3_3d(worldPosQ.x(), worldPosQ.y(), worldPosQ.z());
gp_Pnt p2_3d, p4_3d;
gp_Pnt2d p1_2d(gp_Vec(plane.Location(), p1_3d).Dot(plane.XDirection()), gp_Vec(plane.Location(), p1_3d).Dot(plane.YDirection())); QVector3D mousePos = m_viewport->unproject(m_viewport->currentMousePos(), m_viewport->currentPlane());
gp_Pnt2d p3_2d(gp_Vec(plane.Location(), p3_3d).Dot(plane.XDirection()), gp_Vec(plane.Location(), p3_3d).Dot(plane.YDirection()));
gp_Pnt2d p2_2d(p3_2d.X(), p1_2d.Y());
p2_3d = ElCLib::To3d(plane, p2_2d);
double w = qAbs(p3_2d.X() - p1_2d.X()); if (widthFromInput || heightFromInput) {
double h = qAbs(p3_2d.Y() - p1_2d.Y()); QVector3D mouseDir = mousePos - p1_3d;
double current_w, current_h;
painter.setRenderHint(QPainter::Antialiasing); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
QFontMetrics fm(painter.font()); current_w = qAbs(mouseDir.x());
current_h = qAbs(mouseDir.y());
QVector3D p1_q(p1_3d.X(), p1_3d.Y(), p1_3d.Z()); } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
QVector3D p2_q(p2_3d.X(), p2_3d.Y(), p2_3d.Z()); current_w = qAbs(mouseDir.x());
QVector3D p3_q(p3_3d.X(), p3_3d.Y(), p3_3d.Z()); current_h = qAbs(mouseDir.z());
} else { // YZ
// Width dimension current_w = qAbs(mouseDir.y());
QVector3D widthTextPos3D = (p1_q + p2_q) / 2.0f; current_h = qAbs(mouseDir.z());
QVector3D screenPosW = m_viewport->project(widthTextPos3D, modelView, projection, m_viewport->rect()); }
if (screenPosW.z() < 1.0f) { double rect_w = widthFromInput ? inputWidth : current_w;
QString widthText = widthFromInput ? widthInput : QString::number(w, 'f', 2); double rect_h = heightFromInput ? inputHeight : current_h;
QRect textRect = fm.boundingRect(widthText + "__"); int signX = (mouseDir.x() >= 0) ? 1 : -1;
textRect.moveCenter(screenPosW.toPoint() + QPoint(0, (p3_2d.Y() > p1_2d.Y()) ? -15 : 15)); int signY = (mouseDir.y() >= 0) ? 1 : -1;
if (m_viewport->property("dimensionEditMode").toString() == "width") { int signZ = (mouseDir.z() >= 0) ? 1 : -1;
painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(64, 128, 255)); worldPos = p1_3d;
if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
worldPos.setX(p1_3d.x() + signX * rect_w);
worldPos.setY(p1_3d.y() + signY * rect_h);
} else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
worldPos.setX(p1_3d.x() + signX * rect_w);
worldPos.setZ(p1_3d.z() + signZ * rect_h);
} else { // YZ
worldPos.setY(p1_3d.y() + signY * rect_w);
worldPos.setZ(p1_3d.z() + signZ * rect_h);
}
} else { } else {
painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(50, 50, 50)); worldPos = mousePos;
if (m_viewport->isSnappingOrigin()) {
worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0);
} else if (m_viewport->isSnappingVertex()) {
worldPos.setX(m_viewport->snapVertex().X()); worldPos.setY(m_viewport->snapVertex().Y()); worldPos.setZ(m_viewport->snapVertex().Z());
}
} }
painter.setPen(Qt::white); QVector3D p3_3d = worldPos;
painter.drawText(textRect, Qt::AlignCenter, widthText); QVector3D p2_3d, p4_3d;
}
// Height dimension double w, h;
QVector3D heightTextPos3D = (p2_q + p3_q) / 2.0f;
QVector3D screenPosH = m_viewport->project(heightTextPos3D, modelView, projection, m_viewport->rect()); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
if (screenPosH.z() < 1.0f) { p2_3d.setX(p3_3d.x()); p2_3d.setY(p1_3d.y()); p2_3d.setZ(p1_3d.z());
QString heightText = heightFromInput ? heightInput : QString::number(h, 'f', 2); p4_3d.setX(p1_3d.x()); p4_3d.setY(p3_3d.y()); p4_3d.setZ(p1_3d.z());
QRect textRect = fm.boundingRect(heightText + "__"); w = qAbs(p3_3d.x() - p1_3d.x());
textRect.moveCenter(screenPosH.toPoint() + QPoint((p3_2d.X() > p1_2d.X()) ? 15 : -15, 0)); h = qAbs(p3_3d.y() - p1_3d.y());
if (m_viewport->property("dimensionEditMode").toString() == "height") { } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(64, 128, 255)); p2_3d.setX(p3_3d.x()); p2_3d.setY(p1_3d.y()); p2_3d.setZ(p1_3d.z());
} else { p4_3d.setX(p1_3d.x()); p4_3d.setY(p1_3d.y()); p4_3d.setZ(p3_3d.z());
painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(50, 50, 50)); 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);
QFontMetrics fm(painter.font());
// Width dimension
QVector3D widthTextPos3D = (p1_3d + p2_3d) / 2.0f;
QVector3D screenPosW = m_viewport->project(widthTextPos3D, modelView, projection, m_viewport->rect());
if (screenPosW.z() < 1.0f) {
QString widthText = widthFromInput ? widthInput : QString::number(w, 'f', 2);
QRect textRect = fm.boundingRect(widthText + "__");
textRect.moveCenter(screenPosW.toPoint() + QPoint(0, (p3_3d.z() > p1_3d.z() || p3_3d.y() > p1_3d.y()) ? -15 : 15));
if (m_viewport->property("dimensionEditMode").toString() == "width") {
painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(64, 128, 255));
} else {
painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(50, 50, 50));
}
painter.setPen(Qt::white);
painter.drawText(textRect, Qt::AlignCenter, widthText);
}
// Height dimension
QVector3D heightTextPos3D = (p2_3d + p3_3d) / 2.0f;
QVector3D screenPosH = m_viewport->project(heightTextPos3D, modelView, projection, m_viewport->rect());
if (screenPosH.z() < 1.0f) {
QString heightText = heightFromInput ? heightInput : QString::number(h, 'f', 2);
QRect textRect = fm.boundingRect(heightText + "__");
textRect.moveCenter(screenPosH.toPoint() + QPoint((p3_3d.x() > p1_3d.x()) ? 15 : -15, 0));
if (m_viewport->property("dimensionEditMode").toString() == "height") {
painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(64, 128, 255));
} else {
painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(50, 50, 50));
}
painter.setPen(Qt::white);
painter.drawText(textRect, Qt::AlignCenter, heightText);
} }
painter.setPen(Qt::white);
painter.drawText(textRect, Qt::AlignCenter, heightText);
} }
} }
+1 -1
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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
+16 -67
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3 (or later) // License: GPLv3, see LICENSE.txt
// 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,44 +10,11 @@
#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), m_plane(gp_Pnt(0, 0, 0), gp::DZ()) : Feature(name)
{ {
BRep_Builder builder;
TopoDS_Compound compound;
builder.MakeCompound(compound);
m_shape = compound;
} }
SketchFeature::~SketchFeature() SketchFeature::~SketchFeature()
@@ -60,12 +27,12 @@ QString SketchFeature::type() const
return "Sketch"; return "Sketch";
} }
void SketchFeature::setPlane(const gp_Ax2& plane) void SketchFeature::setPlane(SketchPlane plane)
{ {
m_plane = plane; m_plane = plane;
} }
const gp_Ax2& SketchFeature::plane() const SketchFeature::SketchPlane SketchFeature::plane() const
{ {
return m_plane; return m_plane;
} }
@@ -75,12 +42,6 @@ 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);
@@ -94,14 +55,11 @@ 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"].isObject()) { if (json.contains("plane") && json["plane"].isString()) {
QJsonObject planeJson = json["plane"].toObject(); QString planeStr = json["plane"].toString();
if (planeJson.contains("origin") && planeJson.contains("normal") && planeJson.contains("x_direction")) { if (planeStr == "XY") m_plane = SketchPlane::XY;
gp_Pnt origin = jsonToGpPnt(planeJson["origin"].toObject()); else if (planeStr == "XZ") m_plane = SketchPlane::XZ;
gp_Dir normal = jsonToGpDir(planeJson["normal"].toObject()); else if (planeStr == "YZ") m_plane = SketchPlane::YZ;
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()) {
@@ -129,22 +87,13 @@ 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;
QJsonObject planeJson; switch (m_plane) {
case SketchPlane::XY: planeStr = "XY"; break;
QJsonObject originJson; case SketchPlane::XZ: planeStr = "XZ"; break;
gpPntToJson(m_plane.Location(), originJson); case SketchPlane::YZ: planeStr = "YZ"; break;
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) {
+10 -6
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3 (or later) // License: GPLv3, see LICENSE.txt
// 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,7 +9,6 @@
#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"
@@ -18,16 +17,21 @@ 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(const gp_Ax2& plane); void setPlane(SketchPlane plane);
const gp_Ax2& plane() const; SketchPlane 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;
@@ -36,7 +40,7 @@ public:
void write(QJsonObject &json) const override; void write(QJsonObject &json) const override;
private: private:
gp_Ax2 m_plane; SketchPlane m_plane;
TopoDS_Shape m_shape; TopoDS_Shape m_shape;
QList<SketchObject*> m_objects; QList<SketchObject*> m_objects;
}; };
+51 -56
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3 (or later) // License: GPLv3, see LICENSE.txt
// 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,7 +13,6 @@
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QPainter> #include <QPainter>
#include <QVector> #include <QVector>
#include <gp_Ax2.hxx>
namespace { namespace {
struct GridParams { struct GridParams {
@@ -63,7 +62,7 @@ void SketchGrid::initializeGL()
m_vbo.release(); m_vbo.release();
} }
void SketchGrid::paintGL(const gp_Ax2& plane, QOpenGLShaderProgram* shaderProgram, int colorLoc) void SketchGrid::paintGL(SketchPlane 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);
@@ -78,19 +77,12 @@ void SketchGrid::paintGL(const gp_Ax2& plane, QOpenGLShaderProgram* shaderProgra
QOpenGLContext::currentContext()->extraFunctions()->glBindVertexArray(previous_vao); QOpenGLContext::currentContext()->extraFunctions()->glBindVertexArray(previous_vao);
} }
void SketchGrid::drawGridLines(const gp_Ax2& plane, QOpenGLShaderProgram* shaderProgram, int colorLoc) void SketchGrid::drawGridLines(SketchPlane 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;
@@ -101,14 +93,16 @@ void SketchGrid::drawGridLines(const gp_Ax2& plane, QOpenGLShaderProgram* shader
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) {
QVector3D p1 = originVec + pos * xDirVec - gridSize * yDirVec; current_vector << pos << -gridSize << 0 << pos << gridSize << 0;
QVector3D p2 = originVec + pos * xDirVec + gridSize * yDirVec; current_vector << -gridSize << pos << 0 << gridSize << pos << 0;
current_vector << p1.x() << p1.y() << p1.z() << p2.x() << p2.y() << p2.z(); } else if (plane == XZ) {
current_vector << pos << 0 << -gridSize << pos << 0 << gridSize;
QVector3D p3 = originVec - gridSize * xDirVec + pos * yDirVec; current_vector << -gridSize << 0 << pos << gridSize << 0 << pos;
QVector3D p4 = originVec + gridSize * xDirVec + pos * yDirVec; } else { // YZ
current_vector << p3.x() << p3.y() << p3.z() << p4.x() << p4.y() << p4.z(); current_vector << 0 << pos << -gridSize << 0 << pos << gridSize;
current_vector << 0 << -gridSize << pos << 0 << gridSize << pos;
}
} }
m_vbo.bind(); m_vbo.bind();
@@ -126,51 +120,50 @@ void SketchGrid::drawGridLines(const gp_Ax2& plane, QOpenGLShaderProgram* shader
glDrawArrays(GL_LINES, 0, majorLines.size() / 3); glDrawArrays(GL_LINES, 0, majorLines.size() / 3);
} }
void SketchGrid::drawAxes(const gp_Ax2& plane, QOpenGLShaderProgram* shaderProgram, int colorLoc) void SketchGrid::drawAxes(SketchPlane 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)
vertices.clear(); if (plane == XY || plane == XZ) {
QVector3D p1 = originVec - axisLength * xDirVec; vertices.clear();
QVector3D p2 = originVec + axisLength * xDirVec; vertices << -axisLength << 0 << 0 << axisLength << 0 << 0;
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)
vertices.clear(); if (plane == XY || plane == YZ) {
QVector3D p3 = originVec - axisLength * yDirVec; vertices.clear();
QVector3D p4 = originVec + axisLength * yDirVec; vertices << 0 << -axisLength << 0 << 0 << axisLength << 0;
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 << originVec.x() << originVec.y() << originVec.z(); vertices << 0.0f << 0.0f << 0.0f;
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, const gp_Ax2& plane, const QMatrix4x4& modelView, const QMatrix4x4& projection) void SketchGrid::paintAxisLabels(QPainter& painter, SketchGrid::SketchPlane 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));
@@ -179,21 +172,15 @@ void SketchGrid::paintAxisLabels(QPainter& painter, const gp_Ax2& plane, const Q
const float majorIncrement = params.majorIncrement; const float majorIncrement = params.majorIncrement;
const int range = params.gridSize; const int range = params.gridSize;
const auto& origin = plane.Location(); auto drawLabelsForAxis = [&](int axis_idx) {
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 = originVec + val * axisDir; QVector3D worldCoord;
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
@@ -202,6 +189,14 @@ void SketchGrid::paintAxisLabels(QPainter& painter, const gp_Ax2& plane, const Q
} }
}; };
drawLabelsForAxis(xDirVec); if (plane == SketchGrid::XY) {
drawLabelsForAxis(yDirVec); drawLabelsForAxis(0); // X
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
}
} }
+11 -6
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3 (or later) // License: GPLv3, see LICENSE.txt
// 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,7 +12,6 @@
#include <QMatrix4x4> #include <QMatrix4x4>
#include <QOpenGLVertexArrayObject> #include <QOpenGLVertexArrayObject>
#include <QOpenGLBuffer> #include <QOpenGLBuffer>
#include <gp_Ax2.hxx>
class QOpenGLShaderProgram; class QOpenGLShaderProgram;
class QPainter; class QPainter;
@@ -21,16 +20,22 @@ 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(const gp_Ax2& plane, QOpenGLShaderProgram* shaderProgram, int colorLoc); void paintGL(SketchPlane plane, QOpenGLShaderProgram* shaderProgram, int colorLoc);
void paintAxisLabels(QPainter& painter, const gp_Ax2& plane, const QMatrix4x4& modelView, const QMatrix4x4& projection); void paintAxisLabels(QPainter& painter, SketchPlane plane, const QMatrix4x4& modelView, const QMatrix4x4& projection);
private: private:
void drawGridLines(const gp_Ax2& plane, QOpenGLShaderProgram* shaderProgram, int colorLoc); void drawGridLines(SketchPlane plane, QOpenGLShaderProgram* shaderProgram, int colorLoc);
void drawAxes(const gp_Ax2& plane, QOpenGLShaderProgram* shaderProgram, int colorLoc); void drawAxes(SketchPlane 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 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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
+91 -63
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3 (or later) // License: GPLv3, see LICENSE.txt
// 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,11 +19,6 @@
#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)
{ {
@@ -35,15 +30,23 @@ bool Snapping::update(const QPoint& mousePos)
bool oldIsSnappingVertex = m_isSnappingVertex; bool oldIsSnappingVertex = m_isSnappingVertex;
bool shouldSnap = false; bool shouldSnap = false;
auto currentPlaneOpt = m_viewport->currentPlane(); if (m_viewport->currentPlane() != ViewportWidget::SketchPlane::NONE && m_viewport->activeTool() != static_cast<int>(ApplicationController::ToolType::None)) {
if (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());
const float snapRectHalfSize = 0.0075f * -m_viewport->camera()->zoom(); const float snapRectHalfSize = 0.0075f * -m_viewport->camera()->zoom();
gp_Pnt2d worldPos2d(gp_Vec(plane.Location(), worldPos).Dot(plane.XDirection()), gp_Vec(plane.Location(), worldPos).Dot(plane.YDirection())); switch (m_viewport->currentPlane()) {
shouldSnap = qAbs(worldPos2d.X()) < snapRectHalfSize && qAbs(worldPos2d.Y()) < snapRectHalfSize; case ViewportWidget::SketchPlane::XY:
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;
@@ -52,11 +55,8 @@ bool Snapping::update(const QPoint& mousePos)
} }
m_isSnappingVertex = false; m_isSnappingVertex = false;
if (!m_isSnappingOrigin && m_viewport->document() && currentPlaneOpt && m_viewport->activeTool() != static_cast<int>(ApplicationController::ToolType::None)) { if (!m_isSnappingOrigin && m_viewport->document() && m_viewport->currentPlane() != ViewportWidget::SketchPlane::NONE && m_viewport->activeTool() != static_cast<int>(ApplicationController::ToolType::None)) {
const auto& plane = currentPlaneOpt.value(); QVector3D worldPos = m_viewport->unproject(mousePos, m_viewport->currentPlane());
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,8 +66,20 @@ 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) {
gp_Pnt2d vertex2d(gp_Vec(plane.Location(), vertex).Dot(plane.XDirection()), gp_Vec(plane.Location(), vertex).Dot(plane.YDirection())); bool isClose = false;
bool isClose = qAbs(worldPos2d.X() - vertex2d.X()) < snapRectHalfSize && qAbs(worldPos2d.Y() - vertex2d.Y()) < snapRectHalfSize; switch (m_viewport->currentPlane()) {
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;
@@ -77,23 +89,37 @@ 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;
gp_Pnt2d p1_2d(gp_Vec(rectPlane.Location(), p1).Dot(rectPlane.XDirection()), gp_Vec(rectPlane.Location(), p1).Dot(rectPlane.YDirection())); if (sketch->plane() == SketchFeature::SketchPlane::XY) {
gp_Pnt2d p3_2d(gp_Vec(rectPlane.Location(), p3).Dot(rectPlane.XDirection()), gp_Vec(rectPlane.Location(), p3).Dot(rectPlane.YDirection())); p2.SetCoord(p3.X(), p1.Y(), p1.Z());
p4.SetCoord(p1.X(), p3.Y(), p1.Z());
gp_Pnt2d p2_2d(p3_2d.X(), p1_2d.Y()); } else if (sketch->plane() == SketchFeature::SketchPlane::XZ) {
gp_Pnt2d p4_2d(p1_2d.X(), p3_2d.Y()); p2.SetCoord(p3.X(), p1.Y(), p1.Z());
p4.SetCoord(p1.X(), p1.Y(), p3.Z());
gp_Pnt p2 = ElCLib::To3d(rectPlane, p2_2d); } else if (sketch->plane() == SketchFeature::SketchPlane::YZ) {
gp_Pnt p4 = ElCLib::To3d(rectPlane, p4_2d); p2.SetCoord(p1.X(), p3.Y(), p1.Z());
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) {
gp_Pnt2d vertex2d(gp_Vec(plane.Location(), vertex).Dot(plane.XDirection()), gp_Vec(plane.Location(), vertex).Dot(plane.YDirection())); bool isClose = false;
bool isClose = qAbs(worldPos2d.X() - vertex2d.X()) < snapRectHalfSize && qAbs(worldPos2d.Y() - vertex2d.Y()) < snapRectHalfSize; switch (m_viewport->currentPlane()) {
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;
@@ -118,41 +144,43 @@ 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 auto& o = plane.Location(); const float rectSize = 0.0075f * -m_viewport->camera()->zoom();
QVector3D O(o.X(), o.Y(), o.Z()); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
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; vertices << -rectSize << rectSize << 0 << -rectSize << -rectSize << 0;
QVector3D p4 = O - rectSize * X + rectSize * Y; } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
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(); vertices << -rectSize << 0 << rectSize << -rectSize << 0 << -rectSize;
} 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;
QVector3D V(v.X(), v.Y(), v.Z()); if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) {
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; vertices << v.X() - rectSize << v.Y() + rectSize << v.Z() << v.X() - rectSize << v.Y() - rectSize << v.Z();
QVector3D p4 = V - rectSize * X + rectSize * Y; } else if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XZ) {
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(); vertices << v.X() - rectSize << v.Y() << v.Z() + rectSize << v.X() - rectSize << v.Y() << v.Z() - rectSize;
} 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 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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 (or later) // License: GPLv3, see LICENSE.txt
// 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
+83 -91
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3 (or later) // License: GPLv3, see LICENSE.txt
// 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,15 +33,9 @@
#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 {
@@ -66,7 +60,7 @@ ViewportWidget::ViewportWidget(QWidget *parent)
setMouseTracking(true); setMouseTracking(true);
setFocusPolicy(Qt::StrongFocus); setFocusPolicy(Qt::StrongFocus);
m_currentPlane = gp_Ax2(gp::Origin(), gp::DZ()); m_currentPlane = SketchPlane::XY;
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));
@@ -149,12 +143,12 @@ void ViewportWidget::paintGL()
// Sketch grid rendering // Sketch grid rendering
if (m_isSelectingPlane) { if (m_isSelectingPlane) {
if (m_highlightedPlane) { if (m_highlightedPlane != SketchPlane::NONE) {
m_sketchGrid->paintGL(m_highlightedPlane.value(), m_shaderProgram, m_colorLoc); m_sketchGrid->paintGL(static_cast<SketchGrid::SketchPlane>(m_highlightedPlane), m_shaderProgram, m_colorLoc);
} }
} }
if (m_currentPlane) { if (m_currentPlane != SketchPlane::NONE) {
m_sketchGrid->paintGL(m_currentPlane.value(), m_shaderProgram, m_colorLoc); m_sketchGrid->paintGL(static_cast<SketchGrid::SketchPlane>(m_currentPlane), m_shaderProgram, m_colorLoc);
} }
if (m_isSelectingPlane) { if (m_isSelectingPlane) {
@@ -211,8 +205,8 @@ void ViewportWidget::paintGL()
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
QPainter painter(this); QPainter painter(this);
if (m_currentPlane) { if (m_currentPlane != SketchPlane::NONE) {
m_sketchGrid->paintAxisLabels(painter, m_currentPlane.value(), model, projection); m_sketchGrid->paintAxisLabels(painter, static_cast<SketchGrid::SketchPlane>(m_currentPlane), 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());
@@ -239,10 +233,8 @@ 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)) {
if (m_currentPlane) { m_camera->startRotation(unproject(event->pos(), m_currentPlane));
m_camera->startRotation(unproject(event->pos(), m_currentPlane.value())); update();
update();
}
} }
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
@@ -253,10 +245,10 @@ void ViewportWidget::mousePressEvent(QMouseEvent *event)
} }
if (m_isSelectingPlane) { if (m_isSelectingPlane) {
if (m_highlightedPlane) { if (m_highlightedPlane != SketchPlane::NONE) {
emit planeSelected(m_highlightedPlane.value()); emit planeSelected(m_highlightedPlane);
m_isSelectingPlane = false; m_isSelectingPlane = false;
m_highlightedPlane.reset(); m_highlightedPlane = SketchPlane::NONE;
update(); update();
} }
return; return;
@@ -276,17 +268,8 @@ void ViewportWidget::mouseMoveEvent(QMouseEvent *event)
m_currentMousePos = event->pos(); m_currentMousePos = event->pos();
if (m_isSelectingPlane) { if (m_isSelectingPlane) {
auto newHighlight = checkPlaneSelection(m_currentMousePos); SketchPlane newHighlight = checkPlaneSelection(m_currentMousePos);
bool needsUpdate = newHighlight.has_value() != m_highlightedPlane.has_value(); if (newHighlight != m_highlightedPlane) {
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();
} }
@@ -306,10 +289,8 @@ void ViewportWidget::mouseMoveEvent(QMouseEvent *event)
void ViewportWidget::wheelEvent(QWheelEvent *event) void ViewportWidget::wheelEvent(QWheelEvent *event)
{ {
if (m_currentPlane) { QVector3D worldPos = unproject(event->position().toPoint(), 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)
@@ -322,8 +303,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.reset(); m_highlightedPlane = SketchPlane::NONE;
m_currentPlane = gp_Ax2(gp::Origin(), gp::DZ()); m_currentPlane = SketchPlane::XY;
update(); update();
return; return;
} }
@@ -388,19 +369,19 @@ bool ViewportWidget::focusNextPrevChild(bool next)
return QOpenGLWidget::focusNextPrevChild(next); return QOpenGLWidget::focusNextPrevChild(next);
} }
void ViewportWidget::onSketchModeStarted(const gp_Ax2& plane) void ViewportWidget::onSketchModeStarted(SketchPlane plane)
{ {
m_currentPlane = plane; m_currentPlane = plane;
m_camera->saveState(); m_camera->saveState();
m_camera->animateToPlaneView(plane); m_camera->animateToPlaneView(static_cast<int>(plane));
} }
void ViewportWidget::onPlaneSelectionModeStarted() void ViewportWidget::onPlaneSelectionModeStarted()
{ {
m_isSelectingPlane = true; m_isSelectingPlane = true;
m_highlightedPlane.reset(); m_highlightedPlane = SketchPlane::NONE;
m_currentPlane.reset(); m_currentPlane = SketchPlane::NONE;
update(); update();
} }
@@ -412,7 +393,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 = gp_Ax2(gp::Origin(), gp::DZ()); m_currentPlane = SketchPlane::XY;
update(); update();
} }
@@ -484,7 +465,7 @@ void ViewportWidget::onActiveToolChanged(int tool)
} }
} }
QVector3D ViewportWidget::unproject(const QPoint& screenPos, const gp_Ax2& plane) QVector3D ViewportWidget::unproject(const QPoint& screenPos, SketchPlane plane)
{ {
QMatrix4x4 model = m_camera->modelViewMatrix(); QMatrix4x4 model = m_camera->modelViewMatrix();
@@ -513,13 +494,17 @@ QVector3D ViewportWidget::unproject(const QPoint& screenPos, const gp_Ax2& plane
QVector3D rayOrigin(nearPoint_world); QVector3D rayOrigin(nearPoint_world);
QVector3D rayDir = (QVector3D(farPoint_world) - rayOrigin).normalized(); QVector3D rayDir = (QVector3D(farPoint_world) - rayOrigin).normalized();
const auto& planeNormalDir = plane.Direction(); QVector3D planeNormal;
QVector3D planeNormal(planeNormalDir.X(), planeNormalDir.Y(), planeNormalDir.Z()); switch (plane) {
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) {
const auto& planeOriginPnt = plane.Location(); QVector3D p0(0,0,0);
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;
} }
@@ -553,11 +538,20 @@ void ViewportWidget::drawSketch(const SketchFeature* sketch)
const int numSegments = 64; const int numSegments = 64;
QVector3D u_axis, v_axis; QVector3D u_axis, v_axis;
const auto& plane = sketch->plane(); switch (sketch->plane()) {
const auto& xDir = plane.XDirection(); case SketchFeature::SketchPlane::XY: // Top
const auto& yDir = plane.YDirection(); u_axis = QVector3D(1, 0, 0);
u_axis = QVector3D(xDir.X(), xDir.Y(), xDir.Z()); v_axis = QVector3D(0, 1, 0);
v_axis = QVector3D(yDir.X(), yDir.Y(), yDir.Z()); break;
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);
@@ -571,32 +565,34 @@ 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& plane = sketch->plane(); const auto& p1 = rect->corner1();
const auto& p1_3d = rect->corner1(); const auto& p3 = rect->corner2();
const auto& p3_3d = rect->corner2();
gp_Pnt2d p1_2d(gp_Vec(plane.Location(), p1_3d).Dot(plane.XDirection()), gp_Vec(plane.Location(), p1_3d).Dot(plane.YDirection())); gp_Pnt p2, p4;
gp_Pnt2d p3_2d(gp_Vec(plane.Location(), p3_3d).Dot(plane.XDirection()), gp_Vec(plane.Location(), p3_3d).Dot(plane.YDirection())); if (sketch->plane() == SketchFeature::SketchPlane::XY) {
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());
}
gp_Pnt2d p2_2d(p3_2d.X(), p1_2d.Y()); lineVertices << p1.X() << p1.Y() << p1.Z();
gp_Pnt2d p4_2d(p1_2d.X(), p3_2d.Y()); lineVertices << p2.X() << p2.Y() << p2.Z();
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();
gp_Pnt p2_3d = ElCLib::To3d(plane, p2_2d); vertexCounts[p1] += 2;
gp_Pnt p4_3d = ElCLib::To3d(plane, p4_2d); vertexCounts[p2] += 2;
vertexCounts[p3] += 2;
lineVertices << p1_3d.X() << p1_3d.Y() << p1_3d.Z(); vertexCounts[p4] += 2;
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;
} }
} }
@@ -715,56 +711,52 @@ 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 && m_highlightedPlane->Direction().IsEqual(gp::DZ(), 1e-9)); drawPlane(xyQuad, m_highlightedPlane == SketchPlane::XY);
// 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 && m_highlightedPlane->Direction().IsEqual(gp::DY(), 1e-9)); drawPlane(xzQuad, m_highlightedPlane == SketchPlane::XZ);
// 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 && m_highlightedPlane->Direction().IsEqual(gp::DX(), 1e-9)); drawPlane(yzQuad, m_highlightedPlane == SketchPlane::YZ);
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND); glDisable(GL_BLEND);
} }
std::optional<gp_Ax2> ViewportWidget::checkPlaneSelection(const QPoint& screenPos) ViewportWidget::SketchPlane 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, yzPlane); intersection = unproject(screenPos, SketchPlane::YZ);
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 gp_Ax2(gp_Pnt(0, -planeOffset, planeOffset), gp::DX()); return SketchPlane::YZ;
} }
// XZ plane (Front) // XZ plane (Front)
intersection = unproject(screenPos, xzPlane); intersection = unproject(screenPos, SketchPlane::XZ);
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 gp_Ax2(gp_Pnt(planeOffset, 0, planeOffset), gp::DY()); return SketchPlane::XZ;
} }
// XY plane (Top) // XY plane (Top)
intersection = unproject(screenPos, xyPlane); intersection = unproject(screenPos, SketchPlane::XY);
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 gp_Ax2(gp_Pnt(planeOffset, -planeOffset, 0), gp::DZ()); return SketchPlane::XY;
} }
return std::nullopt; return SketchPlane::NONE;
} }
+15 -10
View File
@@ -1,6 +1,6 @@
// Unnamed CAD Software // Unnamed CAD Software
// //
// License: GPLv3 (or later) // License: GPLv3, see LICENSE.txt
// 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,8 +15,6 @@
#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>
@@ -37,19 +35,26 @@ 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, const gp_Ax2& plane); QVector3D unproject(const QPoint& screenPos, SketchPlane 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; }
std::optional<gp_Ax2> currentPlane() const { return m_currentPlane; } SketchPlane 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;
@@ -64,7 +69,7 @@ public:
void deactivateActiveTool(); void deactivateActiveTool();
public slots: public slots:
void onSketchModeStarted(const gp_Ax2& plane); void onSketchModeStarted(SketchPlane plane);
void onSketchModeEnded(); void onSketchModeEnded();
void onPlaneSelectionModeStarted(); void onPlaneSelectionModeStarted();
void onActiveToolChanged(int tool); void onActiveToolChanged(int tool);
@@ -73,7 +78,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(const gp_Ax2& plane); void planeSelected(SketchPlane plane);
void toolDeactivated(); void toolDeactivated();
private slots: private slots:
@@ -95,7 +100,7 @@ private:
void initShaders(); void initShaders();
void drawSketch(const SketchFeature* sketch); void drawSketch(const SketchFeature* sketch);
void drawSelectionPlanes(); void drawSelectionPlanes();
std::optional<gp_Ax2> checkPlaneSelection(const QPoint& screenPos); ViewportWidget::SketchPlane checkPlaneSelection(const QPoint& screenPos);
QMatrix4x4 projection; QMatrix4x4 projection;
QOpenGLShaderProgram* m_shaderProgram = nullptr; QOpenGLShaderProgram* m_shaderProgram = nullptr;
@@ -111,10 +116,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;
std::optional<gp_Ax2> m_currentPlane; SketchPlane m_currentPlane = SketchPlane::NONE;
bool m_isSelectingPlane = false; bool m_isSelectingPlane = false;
std::optional<gp_Ax2> m_highlightedPlane; SketchPlane m_highlightedPlane = SketchPlane::NONE;
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 (or later) // License: GPLv3, see LICENSE.txt
// 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