Compare commits

19 Commits

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