Compare commits
10
Commits
1ebe10dcee
...
b2d5cd19d4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b2d5cd19d4 | ||
|
|
d89b7e42bc | ||
|
|
9d72fe2155 | ||
|
|
93282fce52 | ||
|
|
a18435bb15 | ||
|
|
ec75ab41c5 | ||
|
|
aaaf9a44ff | ||
|
|
bc2e84a537 | ||
|
|
f842555582 | ||
|
|
a980ad52be |
@@ -17,11 +17,14 @@
|
|||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
MainWindow::MainWindow(ApplicationController* appController, QWidget *parent)
|
MainWindow::MainWindow(ApplicationController* appController, QWidget *parent)
|
||||||
: QMainWindow(parent)
|
: QMainWindow(parent)
|
||||||
, m_appController(appController)
|
, m_appController(appController)
|
||||||
{
|
{
|
||||||
|
qApp->installEventFilter(this);
|
||||||
setWindowTitle("OpenCAD");
|
setWindowTitle("OpenCAD");
|
||||||
resize(1920, 1080);
|
resize(1920, 1080);
|
||||||
|
|
||||||
@@ -204,3 +207,19 @@ void MainWindow::updateWindowTitle(const QString& filePath)
|
|||||||
shownName = "Untitled";
|
shownName = "Untitled";
|
||||||
setWindowTitle(tr("%1[*] - %2").arg(QFileInfo(shownName).fileName(), tr("OpenCAD")));
|
setWindowTitle(tr("%1[*] - %2").arg(QFileInfo(shownName).fileName(), tr("OpenCAD")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
|
||||||
|
{
|
||||||
|
if (m_appController->activeTool() != ApplicationController::ToolType::None && event->type() == QEvent::KeyPress) {
|
||||||
|
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||||
|
if (keyEvent->key() == Qt::Key_Tab || keyEvent->key() == Qt::Key_Backtab) {
|
||||||
|
if (watched == m_viewport) {
|
||||||
|
return false; // Let the viewport handle its own event
|
||||||
|
}
|
||||||
|
// Forward event to viewport and consume it
|
||||||
|
QApplication::sendEvent(m_viewport, keyEvent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QMainWindow::eventFilter(watched, event);
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
|
||||||
|
class QEvent;
|
||||||
class ViewportWidget;
|
class ViewportWidget;
|
||||||
class Document;
|
class Document;
|
||||||
class Feature;
|
class Feature;
|
||||||
@@ -29,6 +30,9 @@ private slots:
|
|||||||
void exitSketchMode();
|
void exitSketchMode();
|
||||||
void updateWindowTitle(const QString& filePath);
|
void updateWindowTitle(const QString& filePath);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ApplicationController* m_appController;
|
ApplicationController* m_appController;
|
||||||
ViewportWidget *m_viewport;
|
ViewportWidget *m_viewport;
|
||||||
|
|||||||
+637
-21
@@ -24,7 +24,7 @@
|
|||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
#include <QOpenGLShaderProgram>
|
#include <QOpenGLShaderProgram>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QMap>
|
#include <map>
|
||||||
|
|
||||||
struct PntComparator {
|
struct PntComparator {
|
||||||
bool operator()(const gp_Pnt& a, const gp_Pnt& b) const {
|
bool operator()(const gp_Pnt& a, const gp_Pnt& b) const {
|
||||||
@@ -198,7 +198,98 @@ void ViewportWidget::paintGL()
|
|||||||
|
|
||||||
if (m_isDefiningLine && m_activeTool == static_cast<int>(ApplicationController::ToolType::Line)) {
|
if (m_isDefiningLine && m_activeTool == static_cast<int>(ApplicationController::ToolType::Line)) {
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
QVector3D worldPos = unproject(m_currentMousePos, m_currentPlane);
|
QVector3D worldPos;
|
||||||
|
QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
|
||||||
|
|
||||||
|
QString dimInput = property("dimensionInput").toString();
|
||||||
|
QString angleInput = property("angleInput").toString();
|
||||||
|
bool lengthFromInput = false;
|
||||||
|
bool angleFromInput = false;
|
||||||
|
double inputLength = 0;
|
||||||
|
double inputAngleDegrees = 0;
|
||||||
|
|
||||||
|
if (!dimInput.isEmpty()) {
|
||||||
|
bool ok;
|
||||||
|
inputLength = dimInput.toDouble(&ok);
|
||||||
|
if (ok) lengthFromInput = true;
|
||||||
|
}
|
||||||
|
if (!angleInput.isEmpty()) {
|
||||||
|
bool ok;
|
||||||
|
inputAngleDegrees = angleInput.toDouble(&ok);
|
||||||
|
if (ok) angleFromInput = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (angleFromInput) {
|
||||||
|
QVector3D refDir;
|
||||||
|
if (property("isChainedLine").toBool()) {
|
||||||
|
refDir = property("previousLineDirection").value<QVector3D>();
|
||||||
|
} else {
|
||||||
|
if (m_currentPlane == SketchPlane::XY || m_currentPlane == SketchPlane::XZ) {
|
||||||
|
refDir = QVector3D(1, 0, 0);
|
||||||
|
} else { // YZ
|
||||||
|
refDir = QVector3D(0, 1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector3D currentMouseWorldPos = unproject(m_currentMousePos, m_currentPlane);
|
||||||
|
QVector3D mouseVec = currentMouseWorldPos - startPos;
|
||||||
|
|
||||||
|
// Quadrant snapping
|
||||||
|
double mouseAngle;
|
||||||
|
if (m_currentPlane == SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.x()));
|
||||||
|
else if (m_currentPlane == SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVec.y(), mouseVec.x()));
|
||||||
|
else mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.y()));
|
||||||
|
|
||||||
|
double refAngle;
|
||||||
|
if (m_currentPlane == SketchPlane::XY) refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.x()));
|
||||||
|
else if (m_currentPlane == SketchPlane::XZ) refAngle = qRadiansToDegrees(atan2(refDir.y(), refDir.x()));
|
||||||
|
else refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.y()));
|
||||||
|
|
||||||
|
double relativeMouseAngle = mouseAngle - refAngle;
|
||||||
|
while (relativeMouseAngle <= -180.0) relativeMouseAngle += 360.0;
|
||||||
|
while (relativeMouseAngle > 180.0) relativeMouseAngle -= 360.0;
|
||||||
|
|
||||||
|
double snappedAngle = 0;
|
||||||
|
if (relativeMouseAngle >= -45 && relativeMouseAngle < 45) {
|
||||||
|
snappedAngle = inputAngleDegrees;
|
||||||
|
} else if (relativeMouseAngle >= 45 && relativeMouseAngle < 135) {
|
||||||
|
snappedAngle = 180 - inputAngleDegrees;
|
||||||
|
} else if (relativeMouseAngle >= 135 || relativeMouseAngle < -135) {
|
||||||
|
snappedAngle = inputAngleDegrees + 180.0;
|
||||||
|
} else { // -135 to -45
|
||||||
|
snappedAngle = 360 - inputAngleDegrees;
|
||||||
|
}
|
||||||
|
|
||||||
|
double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle);
|
||||||
|
QVector3D finalDir;
|
||||||
|
if (m_currentPlane == SketchPlane::XY) finalDir = QVector3D(cos(finalAngleRad), 0, sin(finalAngleRad));
|
||||||
|
else if (m_currentPlane == SketchPlane::XZ) finalDir = QVector3D(cos(finalAngleRad), sin(finalAngleRad), 0);
|
||||||
|
else finalDir = QVector3D(0, cos(finalAngleRad), sin(finalAngleRad));
|
||||||
|
|
||||||
|
double lineLength;
|
||||||
|
if (lengthFromInput) {
|
||||||
|
lineLength = inputLength;
|
||||||
|
} else {
|
||||||
|
lineLength = QVector3D::dotProduct(mouseVec, finalDir);
|
||||||
|
if (lineLength < 0) lineLength = 0;
|
||||||
|
}
|
||||||
|
worldPos = startPos + lineLength * finalDir;
|
||||||
|
|
||||||
|
} else if (lengthFromInput) {
|
||||||
|
QVector3D currentMouseWorldPos = unproject(m_currentMousePos, m_currentPlane);
|
||||||
|
QVector3D dir = (currentMouseWorldPos - startPos);
|
||||||
|
if (dir.length() > 1e-6) {
|
||||||
|
dir.normalize();
|
||||||
|
worldPos = startPos + inputLength * dir;
|
||||||
|
} else {
|
||||||
|
if (m_currentPlane == SketchPlane::XY || m_currentPlane == SketchPlane::XZ) {
|
||||||
|
worldPos = startPos + QVector3D(inputLength, 0, 0);
|
||||||
|
} else {
|
||||||
|
worldPos = startPos + QVector3D(0, inputLength, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
worldPos = unproject(m_currentMousePos, m_currentPlane);
|
||||||
if (m_isSnappingOrigin) {
|
if (m_isSnappingOrigin) {
|
||||||
worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0);
|
worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0);
|
||||||
} else if (m_isSnappingVertex) {
|
} else if (m_isSnappingVertex) {
|
||||||
@@ -212,6 +303,8 @@ void ViewportWidget::paintGL()
|
|||||||
else if (m_currentPlane == SketchPlane::XZ) worldPos.setX(m_firstLinePoint.X());
|
else if (m_currentPlane == SketchPlane::XZ) worldPos.setX(m_firstLinePoint.X());
|
||||||
else if (m_currentPlane == SketchPlane::YZ) worldPos.setY(m_firstLinePoint.Y());
|
else if (m_currentPlane == SketchPlane::YZ) worldPos.setY(m_firstLinePoint.Y());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vertices << m_firstLinePoint.X() << m_firstLinePoint.Y() << m_firstLinePoint.Z();
|
vertices << m_firstLinePoint.X() << m_firstLinePoint.Y() << m_firstLinePoint.Z();
|
||||||
vertices << worldPos.x() << worldPos.y() << worldPos.z();
|
vertices << worldPos.x() << worldPos.y() << worldPos.z();
|
||||||
|
|
||||||
@@ -220,7 +313,150 @@ void ViewportWidget::paintGL()
|
|||||||
m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
|
m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
|
||||||
glDrawArrays(GL_LINES, 0, 2);
|
glDrawArrays(GL_LINES, 0, 2);
|
||||||
|
|
||||||
if (m_isSnappingHorizontal || m_isSnappingVertical) {
|
// Draw dimension line
|
||||||
|
QVector3D lineVec = worldPos - startPos;
|
||||||
|
float lineLength = lineVec.length();
|
||||||
|
|
||||||
|
if (lineLength > 1e-6) {
|
||||||
|
vertices.clear();
|
||||||
|
|
||||||
|
QVector3D perpVec;
|
||||||
|
if (m_currentPlane == SketchPlane::XY) {
|
||||||
|
perpVec = QVector3D(-lineVec.z(), 0, lineVec.x()).normalized();
|
||||||
|
} else if (m_currentPlane == SketchPlane::XZ) {
|
||||||
|
perpVec = QVector3D(-lineVec.y(), lineVec.x(), 0).normalized();
|
||||||
|
} else if (m_currentPlane == SketchPlane::YZ) {
|
||||||
|
perpVec = QVector3D(0, -lineVec.z(), lineVec.y()).normalized();
|
||||||
|
}
|
||||||
|
|
||||||
|
float offset = 0.05f * -m_camera->zoom();
|
||||||
|
QVector3D dimStart = startPos + offset * perpVec;
|
||||||
|
QVector3D dimEnd = worldPos + offset * perpVec;
|
||||||
|
|
||||||
|
vertices << dimStart.x() << dimStart.y() << dimStart.z();
|
||||||
|
vertices << dimEnd.x() << dimEnd.y() << dimEnd.z();
|
||||||
|
|
||||||
|
float arrowLength = 0.02f * -m_camera->zoom();
|
||||||
|
float arrowWidth = 0.005f * -m_camera->zoom();
|
||||||
|
QVector3D lineDir = lineVec.normalized();
|
||||||
|
|
||||||
|
QVector3D arrow_base_end = dimEnd - arrowLength * lineDir;
|
||||||
|
QVector3D arrowP1_end = arrow_base_end + arrowWidth * perpVec;
|
||||||
|
QVector3D arrowP2_end = arrow_base_end - arrowWidth * perpVec;
|
||||||
|
vertices << dimEnd.x() << dimEnd.y() << dimEnd.z();
|
||||||
|
vertices << arrowP1_end.x() << arrowP1_end.y() << arrowP1_end.z();
|
||||||
|
vertices << dimEnd.x() << dimEnd.y() << dimEnd.z();
|
||||||
|
vertices << arrowP2_end.x() << arrowP2_end.y() << arrowP2_end.z();
|
||||||
|
|
||||||
|
QVector3D arrow_base_start = dimStart + arrowLength * lineDir;
|
||||||
|
QVector3D arrowP1_start = arrow_base_start + arrowWidth * perpVec;
|
||||||
|
QVector3D arrowP2_start = arrow_base_start - arrowWidth * perpVec;
|
||||||
|
vertices << dimStart.x() << dimStart.y() << dimStart.z();
|
||||||
|
vertices << arrowP1_start.x() << arrowP1_start.y() << arrowP1_start.z();
|
||||||
|
vertices << dimStart.x() << dimStart.y() << dimStart.z();
|
||||||
|
vertices << arrowP2_start.x() << arrowP2_start.y() << arrowP2_start.z();
|
||||||
|
|
||||||
|
m_shaderProgram->setUniformValue(m_colorLoc, QVector4D(0.7f, 0.7f, 0.7f, 1.0f));
|
||||||
|
glLineWidth(1.0f);
|
||||||
|
m_vbo.bind();
|
||||||
|
m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
|
||||||
|
glDrawArrays(GL_LINES, 0, vertices.size() / 3);
|
||||||
|
glLineWidth(2.0f);
|
||||||
|
|
||||||
|
// Draw angle dimension
|
||||||
|
vertices.clear();
|
||||||
|
QVector3D refDir;
|
||||||
|
if (property("isChainedLine").toBool()) {
|
||||||
|
refDir = property("previousLineDirection").value<QVector3D>();
|
||||||
|
} else {
|
||||||
|
if (m_currentPlane == SketchPlane::XY || m_currentPlane == SketchPlane::XZ) refDir = QVector3D(1, 0, 0);
|
||||||
|
else refDir = QVector3D(0, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
double refAngle, lineAngle;
|
||||||
|
if (m_currentPlane == SketchPlane::XY) {
|
||||||
|
refAngle = atan2(refDir.z(), refDir.x());
|
||||||
|
lineAngle = atan2(lineVec.z(), lineVec.x());
|
||||||
|
} else if (m_currentPlane == SketchPlane::XZ) {
|
||||||
|
refAngle = atan2(refDir.y(), refDir.x());
|
||||||
|
lineAngle = atan2(lineVec.y(), lineVec.x());
|
||||||
|
} else { // YZ
|
||||||
|
refAngle = atan2(refDir.z(), refDir.y());
|
||||||
|
lineAngle = atan2(lineVec.z(), lineVec.y());
|
||||||
|
}
|
||||||
|
|
||||||
|
double angleDiff = lineAngle - refAngle;
|
||||||
|
while (angleDiff <= -M_PI) angleDiff += 2 * M_PI;
|
||||||
|
while (angleDiff > M_PI) angleDiff -= 2 * M_PI;
|
||||||
|
lineAngle = refAngle + angleDiff;
|
||||||
|
|
||||||
|
const int numSegments = 30;
|
||||||
|
const float radius = 0.1f * -m_camera->zoom();
|
||||||
|
for (int i = 0; i <= numSegments; ++i) {
|
||||||
|
double angle = refAngle + (lineAngle - refAngle) * i / numSegments;
|
||||||
|
QVector3D p;
|
||||||
|
if (m_currentPlane == SketchPlane::XY) p = startPos + radius * QVector3D(cos(angle), 0, sin(angle));
|
||||||
|
else if (m_currentPlane == SketchPlane::XZ) p = startPos + radius * QVector3D(cos(angle), sin(angle), 0);
|
||||||
|
else p = startPos + radius * QVector3D(0, cos(angle), sin(angle));
|
||||||
|
vertices << p.x() << p.y() << p.z();
|
||||||
|
}
|
||||||
|
glLineWidth(1.0f);
|
||||||
|
m_vbo.bind();
|
||||||
|
m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
|
||||||
|
glDrawArrays(GL_LINE_STRIP, 0, vertices.size() / 3);
|
||||||
|
|
||||||
|
// Arrowheads for arc
|
||||||
|
QVector<GLfloat> arrowVertices;
|
||||||
|
float arcArrowLength = 0.02f * -m_camera->zoom();
|
||||||
|
float arcArrowWidth = 0.005f * -m_camera->zoom();
|
||||||
|
|
||||||
|
// End arrowhead
|
||||||
|
QVector3D endPoint(vertices[vertices.size()-3], vertices[vertices.size()-2], vertices[vertices.size()-1]);
|
||||||
|
double endAngle = lineAngle;
|
||||||
|
QVector3D radialDir_end, tangentDir_end;
|
||||||
|
if (m_currentPlane == SketchPlane::XY) {
|
||||||
|
radialDir_end = QVector3D(cos(endAngle), 0, sin(endAngle));
|
||||||
|
tangentDir_end = QVector3D(-sin(endAngle), 0, cos(endAngle));
|
||||||
|
} else if (m_currentPlane == SketchPlane::XZ) {
|
||||||
|
radialDir_end = QVector3D(cos(endAngle), sin(endAngle), 0);
|
||||||
|
tangentDir_end = QVector3D(-sin(endAngle), cos(endAngle), 0);
|
||||||
|
} else {
|
||||||
|
radialDir_end = QVector3D(0, cos(endAngle), sin(endAngle));
|
||||||
|
tangentDir_end = QVector3D(0, -sin(endAngle), cos(endAngle));
|
||||||
|
}
|
||||||
|
QVector3D arc_arrow_base_end = endPoint - 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;
|
||||||
|
arrowVertices << endPoint.x() << endPoint.y() << endPoint.z() << arc_arrowP1_end.x() << arc_arrowP1_end.y() << arc_arrowP1_end.z();
|
||||||
|
arrowVertices << endPoint.x() << endPoint.y() << endPoint.z() << arc_arrowP2_end.x() << arc_arrowP2_end.y() << arc_arrowP2_end.z();
|
||||||
|
|
||||||
|
// Start arrowhead
|
||||||
|
QVector3D startPoint(vertices[0], vertices[1], vertices[2]);
|
||||||
|
double startAngle = refAngle;
|
||||||
|
QVector3D radialDir_start, tangentDir_start;
|
||||||
|
if (m_currentPlane == SketchPlane::XY) {
|
||||||
|
radialDir_start = QVector3D(cos(startAngle), 0, sin(startAngle));
|
||||||
|
tangentDir_start = QVector3D(-sin(startAngle), 0, cos(startAngle));
|
||||||
|
} else if (m_currentPlane == SketchPlane::XZ) {
|
||||||
|
radialDir_start = QVector3D(cos(startAngle), sin(startAngle), 0);
|
||||||
|
tangentDir_start = QVector3D(-sin(startAngle), cos(startAngle), 0);
|
||||||
|
} else {
|
||||||
|
radialDir_start = QVector3D(0, cos(startAngle), sin(startAngle));
|
||||||
|
tangentDir_start = QVector3D(0, -sin(startAngle), cos(startAngle));
|
||||||
|
}
|
||||||
|
QVector3D arc_arrow_base_start = startPoint + 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;
|
||||||
|
arrowVertices << startPoint.x() << startPoint.y() << startPoint.z() << arc_arrowP1_start.x() << arc_arrowP1_start.y() << arc_arrowP1_start.z();
|
||||||
|
arrowVertices << startPoint.x() << startPoint.y() << startPoint.z() << arc_arrowP2_start.x() << arc_arrowP2_start.y() << arc_arrowP2_start.z();
|
||||||
|
|
||||||
|
m_vbo.bind();
|
||||||
|
m_vbo.allocate(arrowVertices.constData(), arrowVertices.size() * sizeof(GLfloat));
|
||||||
|
glDrawArrays(GL_LINES, 0, arrowVertices.size() / 3);
|
||||||
|
glLineWidth(2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lengthFromInput && !angleFromInput && (m_isSnappingHorizontal || m_isSnappingVertical)) {
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
|
QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
|
||||||
QVector3D midPoint = (startPos + worldPos) / 2.0;
|
QVector3D midPoint = (startPos + worldPos) / 2.0;
|
||||||
@@ -273,6 +509,204 @@ void ViewportWidget::paintGL()
|
|||||||
}
|
}
|
||||||
m_featureBrowser->paint(painter, width(), height());
|
m_featureBrowser->paint(painter, width(), height());
|
||||||
|
|
||||||
|
if (m_isDefiningLine && m_activeTool == static_cast<int>(ApplicationController::ToolType::Line)) {
|
||||||
|
QVector3D worldPos;
|
||||||
|
QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
|
||||||
|
QString dimText;
|
||||||
|
QString angleText;
|
||||||
|
|
||||||
|
QString dimInput = property("dimensionInput").toString();
|
||||||
|
QString angleInput = property("angleInput").toString();
|
||||||
|
bool lengthFromInput = false;
|
||||||
|
bool angleFromInput = false;
|
||||||
|
double inputLength = 0;
|
||||||
|
double inputAngleDegrees = 0;
|
||||||
|
double lineLength = 0;
|
||||||
|
|
||||||
|
if (!dimInput.isEmpty()) {
|
||||||
|
bool ok;
|
||||||
|
inputLength = dimInput.toDouble(&ok);
|
||||||
|
if (ok) lengthFromInput = true;
|
||||||
|
}
|
||||||
|
if (!angleInput.isEmpty()) {
|
||||||
|
bool ok;
|
||||||
|
inputAngleDegrees = angleInput.toDouble(&ok);
|
||||||
|
if (ok) angleFromInput = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (angleFromInput) {
|
||||||
|
QVector3D refDir;
|
||||||
|
if (property("isChainedLine").toBool()) {
|
||||||
|
refDir = property("previousLineDirection").value<QVector3D>();
|
||||||
|
} else {
|
||||||
|
if (m_currentPlane == SketchPlane::XY || m_currentPlane == SketchPlane::XZ) {
|
||||||
|
refDir = QVector3D(1, 0, 0);
|
||||||
|
} else { // YZ
|
||||||
|
refDir = QVector3D(0, 1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector3D currentMouseWorldPos = unproject(m_currentMousePos, m_currentPlane);
|
||||||
|
QVector3D mouseVec = currentMouseWorldPos - startPos;
|
||||||
|
|
||||||
|
double mouseAngle;
|
||||||
|
if (m_currentPlane == SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.x()));
|
||||||
|
else if (m_currentPlane == SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVec.y(), mouseVec.x()));
|
||||||
|
else mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.y()));
|
||||||
|
|
||||||
|
double refAngle;
|
||||||
|
if (m_currentPlane == SketchPlane::XY) refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.x()));
|
||||||
|
else if (m_currentPlane == SketchPlane::XZ) refAngle = qRadiansToDegrees(atan2(refDir.y(), refDir.x()));
|
||||||
|
else refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.y()));
|
||||||
|
|
||||||
|
double relativeMouseAngle = mouseAngle - refAngle;
|
||||||
|
while (relativeMouseAngle <= -180.0) relativeMouseAngle += 360.0;
|
||||||
|
while (relativeMouseAngle > 180.0) relativeMouseAngle -= 360.0;
|
||||||
|
|
||||||
|
double snappedAngle = 0;
|
||||||
|
if (relativeMouseAngle >= -45 && relativeMouseAngle < 45) {
|
||||||
|
snappedAngle = inputAngleDegrees;
|
||||||
|
} else if (relativeMouseAngle >= 45 && relativeMouseAngle < 135) {
|
||||||
|
snappedAngle = 180 - inputAngleDegrees;
|
||||||
|
} else if (relativeMouseAngle >= 135 || relativeMouseAngle < -135) {
|
||||||
|
snappedAngle = inputAngleDegrees + 180.0;
|
||||||
|
} else { // -135 to -45
|
||||||
|
snappedAngle = 360 - inputAngleDegrees;
|
||||||
|
}
|
||||||
|
|
||||||
|
double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle);
|
||||||
|
QVector3D finalDir;
|
||||||
|
if (m_currentPlane == SketchPlane::XY) finalDir = QVector3D(cos(finalAngleRad), 0, sin(finalAngleRad));
|
||||||
|
else if (m_currentPlane == SketchPlane::XZ) finalDir = QVector3D(cos(finalAngleRad), sin(finalAngleRad), 0);
|
||||||
|
else finalDir = QVector3D(0, cos(finalAngleRad), sin(finalAngleRad));
|
||||||
|
|
||||||
|
if (lengthFromInput) {
|
||||||
|
lineLength = inputLength;
|
||||||
|
} else {
|
||||||
|
lineLength = QVector3D::dotProduct(mouseVec, finalDir);
|
||||||
|
if (lineLength < 0) lineLength = 0;
|
||||||
|
}
|
||||||
|
worldPos = startPos + lineLength * finalDir;
|
||||||
|
|
||||||
|
} else if (lengthFromInput) {
|
||||||
|
lineLength = inputLength;
|
||||||
|
QVector3D currentMouseWorldPos = unproject(m_currentMousePos, m_currentPlane);
|
||||||
|
QVector3D dir = (currentMouseWorldPos - startPos);
|
||||||
|
if (dir.length() > 1e-6) {
|
||||||
|
dir.normalize();
|
||||||
|
worldPos = startPos + inputLength * dir;
|
||||||
|
} else {
|
||||||
|
if (m_currentPlane == SketchPlane::XY || m_currentPlane == SketchPlane::XZ) {
|
||||||
|
worldPos = startPos + QVector3D(inputLength, 0, 0);
|
||||||
|
} else {
|
||||||
|
worldPos = startPos + QVector3D(0, inputLength, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
worldPos = unproject(m_currentMousePos, m_currentPlane);
|
||||||
|
if (m_isSnappingOrigin) {
|
||||||
|
worldPos.setX(0); worldPos.setY(0); worldPos.setZ(0);
|
||||||
|
} else if (m_isSnappingVertex) {
|
||||||
|
worldPos.setX(m_snapVertex.X()); worldPos.setY(m_snapVertex.Y()); worldPos.setZ(m_snapVertex.Z());
|
||||||
|
} else if (m_isSnappingHorizontal) {
|
||||||
|
if (m_currentPlane == SketchPlane::XY) worldPos.setZ(m_firstLinePoint.Z());
|
||||||
|
else if (m_currentPlane == SketchPlane::XZ) worldPos.setY(m_firstLinePoint.Y());
|
||||||
|
else if (m_currentPlane == SketchPlane::YZ) worldPos.setZ(m_firstLinePoint.Z());
|
||||||
|
} else if (m_isSnappingVertical) {
|
||||||
|
if (m_currentPlane == SketchPlane::XY) worldPos.setX(m_firstLinePoint.X());
|
||||||
|
else if (m_currentPlane == SketchPlane::XZ) worldPos.setX(m_firstLinePoint.X());
|
||||||
|
else if (m_currentPlane == SketchPlane::YZ) worldPos.setY(m_firstLinePoint.Y());
|
||||||
|
}
|
||||||
|
lineLength = (worldPos - startPos).length();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector3D lineVec = worldPos - startPos;
|
||||||
|
if (lineVec.length() > 1e-6) {
|
||||||
|
QVector3D perpVec;
|
||||||
|
if (m_currentPlane == SketchPlane::XY) {
|
||||||
|
perpVec = QVector3D(-lineVec.z(), 0, lineVec.x()).normalized();
|
||||||
|
} else if (m_currentPlane == SketchPlane::XZ) {
|
||||||
|
perpVec = QVector3D(-lineVec.y(), lineVec.x(), 0).normalized();
|
||||||
|
} else if (m_currentPlane == SketchPlane::YZ) {
|
||||||
|
perpVec = QVector3D(0, -lineVec.z(), lineVec.y()).normalized();
|
||||||
|
}
|
||||||
|
|
||||||
|
float offset = 0.05f * -m_camera->zoom();
|
||||||
|
QVector3D dimStart = startPos + offset * perpVec;
|
||||||
|
QVector3D dimEnd = worldPos + offset * perpVec;
|
||||||
|
QVector3D textPos3D = (dimStart + dimEnd) / 2.0f + 0.015f * -m_camera->zoom() * perpVec;
|
||||||
|
|
||||||
|
QVector3D screenPos = project(textPos3D, model, projection, rect());
|
||||||
|
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
QFontMetrics fm(painter.font());
|
||||||
|
|
||||||
|
if (screenPos.z() < 1.0f) {
|
||||||
|
dimText = lengthFromInput ? dimInput : QString::number(lineLength, 'f', 2);
|
||||||
|
|
||||||
|
QRect textRect = fm.boundingRect(dimText + "_");
|
||||||
|
textRect.moveCenter(screenPos.toPoint());
|
||||||
|
|
||||||
|
if (lengthFromInput && property("dimensionEditMode").toString() == "length") {
|
||||||
|
painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(64, 128, 255));
|
||||||
|
} else {
|
||||||
|
painter.fillRect(textRect.adjusted(-4, -2, 4, 2), QColor(50, 50, 50));
|
||||||
|
}
|
||||||
|
painter.setPen(Qt::white);
|
||||||
|
painter.drawText(textRect, Qt::AlignCenter, dimText);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Angle dimension text
|
||||||
|
QVector3D refDir;
|
||||||
|
if (property("isChainedLine").toBool()) {
|
||||||
|
refDir = property("previousLineDirection").value<QVector3D>();
|
||||||
|
} else {
|
||||||
|
if (m_currentPlane == SketchPlane::XY || m_currentPlane == SketchPlane::XZ) refDir = QVector3D(1, 0, 0);
|
||||||
|
else refDir = QVector3D(0, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
double refAngle, lineAngle;
|
||||||
|
if (m_currentPlane == SketchPlane::XY) {
|
||||||
|
refAngle = atan2(refDir.z(), refDir.x());
|
||||||
|
lineAngle = atan2(lineVec.z(), lineVec.x());
|
||||||
|
} else if (m_currentPlane == SketchPlane::XZ) {
|
||||||
|
refAngle = atan2(refDir.y(), refDir.x());
|
||||||
|
lineAngle = atan2(lineVec.y(), lineVec.x());
|
||||||
|
} else { // YZ
|
||||||
|
refAngle = atan2(refDir.z(), refDir.y());
|
||||||
|
lineAngle = atan2(lineVec.z(), lineVec.y());
|
||||||
|
}
|
||||||
|
|
||||||
|
double angleDiffDegrees = qRadiansToDegrees(lineAngle - refAngle);
|
||||||
|
while (angleDiffDegrees <= -180.0) angleDiffDegrees += 360.0;
|
||||||
|
while (angleDiffDegrees > 180.0) angleDiffDegrees -= 360.0;
|
||||||
|
|
||||||
|
angleText = angleFromInput ? angleInput : QString::number(qAbs(angleDiffDegrees), 'f', 1) + QChar(0x00B0);
|
||||||
|
|
||||||
|
const float radius = 0.1f * -m_camera->zoom();
|
||||||
|
double midAngle = refAngle + (lineAngle - refAngle) / 2.0;
|
||||||
|
QVector3D textPos3DAngle;
|
||||||
|
float textOffset = 0.035f * -m_camera->zoom();
|
||||||
|
|
||||||
|
if (m_currentPlane == SketchPlane::XY) textPos3DAngle = startPos + (radius + textOffset) * QVector3D(cos(midAngle), 0, sin(midAngle));
|
||||||
|
else if (m_currentPlane == SketchPlane::XZ) textPos3DAngle = startPos + (radius + textOffset) * QVector3D(cos(midAngle), sin(midAngle), 0);
|
||||||
|
else textPos3DAngle = startPos + (radius + textOffset) * QVector3D(0, cos(midAngle), sin(midAngle));
|
||||||
|
|
||||||
|
QVector3D screenPosAngle = project(textPos3DAngle, model, projection, rect());
|
||||||
|
if (screenPosAngle.z() < 1.0f) {
|
||||||
|
QRect angleTextRect = fm.boundingRect(angleText + "_");
|
||||||
|
angleTextRect.moveCenter(screenPosAngle.toPoint());
|
||||||
|
if (angleFromInput && property("dimensionEditMode").toString() == "angle") {
|
||||||
|
painter.fillRect(angleTextRect.adjusted(-4, -2, 4, 2), QColor(64, 128, 255));
|
||||||
|
} else {
|
||||||
|
painter.fillRect(angleTextRect.adjusted(-4, -2, 4, 2), QColor(50, 50, 50));
|
||||||
|
}
|
||||||
|
painter.setPen(Qt::white);
|
||||||
|
painter.drawText(angleTextRect, Qt::AlignCenter, angleText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
painter.end();
|
painter.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,9 +752,21 @@ void ViewportWidget::mousePressEvent(QMouseEvent *event)
|
|||||||
if (!m_isDefiningLine) {
|
if (!m_isDefiningLine) {
|
||||||
m_firstLinePoint = p;
|
m_firstLinePoint = p;
|
||||||
m_isDefiningLine = true;
|
m_isDefiningLine = true;
|
||||||
|
setProperty("dimensionInput", QVariant(""));
|
||||||
|
setProperty("angleInput", QVariant(""));
|
||||||
|
setProperty("dimensionEditMode", "length");
|
||||||
|
setProperty("isChainedLine", false);
|
||||||
} else {
|
} else {
|
||||||
|
QVector3D start(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
|
||||||
|
QVector3D end(p.X(), p.Y(), p.Z());
|
||||||
|
setProperty("previousLineDirection", QVariant::fromValue((end - start).normalized()));
|
||||||
|
|
||||||
emit lineAdded(m_firstLinePoint, p);
|
emit lineAdded(m_firstLinePoint, p);
|
||||||
m_firstLinePoint = p;
|
m_firstLinePoint = p;
|
||||||
|
setProperty("dimensionInput", QVariant(""));
|
||||||
|
setProperty("angleInput", QVariant(""));
|
||||||
|
setProperty("dimensionEditMode", "length");
|
||||||
|
setProperty("isChainedLine", true);
|
||||||
}
|
}
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
@@ -462,9 +908,137 @@ void ViewportWidget::wheelEvent(QWheelEvent *event)
|
|||||||
|
|
||||||
void ViewportWidget::keyPressEvent(QKeyEvent *event)
|
void ViewportWidget::keyPressEvent(QKeyEvent *event)
|
||||||
{
|
{
|
||||||
|
if (m_isDefiningLine && m_activeTool == static_cast<int>(ApplicationController::ToolType::Line)) {
|
||||||
|
if (event->key() == Qt::Key_Tab) {
|
||||||
|
QString currentMode = property("dimensionEditMode").toString();
|
||||||
|
if (currentMode == "length") {
|
||||||
|
setProperty("dimensionEditMode", "angle");
|
||||||
|
} else {
|
||||||
|
setProperty("dimensionEditMode", "length");
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString editMode = property("dimensionEditMode").toString();
|
||||||
|
const char* propertyName = (editMode == "length") ? "dimensionInput" : "angleInput";
|
||||||
|
QString currentInput = property(propertyName).toString();
|
||||||
|
|
||||||
|
if (event->key() >= Qt::Key_0 && event->key() <= Qt::Key_9) {
|
||||||
|
currentInput += event->text();
|
||||||
|
setProperty(propertyName, currentInput);
|
||||||
|
update();
|
||||||
|
return;
|
||||||
|
} else if (event->key() == Qt::Key_Period) {
|
||||||
|
if (!currentInput.contains('.')) {
|
||||||
|
currentInput += '.';
|
||||||
|
setProperty(propertyName, currentInput);
|
||||||
|
update();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (event->key() == Qt::Key_Backspace) {
|
||||||
|
if (!currentInput.isEmpty()) {
|
||||||
|
currentInput.chop(1);
|
||||||
|
setProperty(propertyName, currentInput);
|
||||||
|
update();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
|
||||||
|
QVector3D worldPos;
|
||||||
|
QVector3D startPos(m_firstLinePoint.X(), m_firstLinePoint.Y(), m_firstLinePoint.Z());
|
||||||
|
// This is duplicated from paintGL to ensure consistent line creation
|
||||||
|
QString dimInput = property("dimensionInput").toString();
|
||||||
|
QString angleInput = property("angleInput").toString();
|
||||||
|
bool lengthFromInput = false;
|
||||||
|
bool angleFromInput = false;
|
||||||
|
double inputLength = 0;
|
||||||
|
double inputAngleDegrees = 0;
|
||||||
|
|
||||||
|
if (!dimInput.isEmpty()) {
|
||||||
|
bool ok;
|
||||||
|
inputLength = dimInput.toDouble(&ok);
|
||||||
|
if (ok) lengthFromInput = true;
|
||||||
|
}
|
||||||
|
if (!angleInput.isEmpty()) {
|
||||||
|
bool ok;
|
||||||
|
inputAngleDegrees = angleInput.toDouble(&ok);
|
||||||
|
if (ok) angleFromInput = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (angleFromInput) {
|
||||||
|
QVector3D refDir;
|
||||||
|
if (property("isChainedLine").toBool()) {
|
||||||
|
refDir = property("previousLineDirection").value<QVector3D>();
|
||||||
|
} else {
|
||||||
|
if (m_currentPlane == SketchPlane::XY || m_currentPlane == SketchPlane::XZ) refDir = QVector3D(1, 0, 0);
|
||||||
|
else refDir = QVector3D(0, 1, 0);
|
||||||
|
}
|
||||||
|
QVector3D currentMouseWorldPos = unproject(m_currentMousePos, m_currentPlane);
|
||||||
|
QVector3D mouseVec = currentMouseWorldPos - startPos;
|
||||||
|
double mouseAngle;
|
||||||
|
if (m_currentPlane == SketchPlane::XY) mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.x()));
|
||||||
|
else if (m_currentPlane == SketchPlane::XZ) mouseAngle = qRadiansToDegrees(atan2(mouseVec.y(), mouseVec.x()));
|
||||||
|
else mouseAngle = qRadiansToDegrees(atan2(mouseVec.z(), mouseVec.y()));
|
||||||
|
double refAngle;
|
||||||
|
if (m_currentPlane == SketchPlane::XY) refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.x()));
|
||||||
|
else if (m_currentPlane == SketchPlane::XZ) refAngle = qRadiansToDegrees(atan2(refDir.y(), refDir.x()));
|
||||||
|
else refAngle = qRadiansToDegrees(atan2(refDir.z(), refDir.y()));
|
||||||
|
double relativeMouseAngle = mouseAngle - refAngle;
|
||||||
|
while (relativeMouseAngle <= -180.0) relativeMouseAngle += 360.0;
|
||||||
|
while (relativeMouseAngle > 180.0) relativeMouseAngle -= 360.0;
|
||||||
|
double snappedAngle = 0;
|
||||||
|
if (relativeMouseAngle >= -45 && relativeMouseAngle < 45) snappedAngle = inputAngleDegrees;
|
||||||
|
else if (relativeMouseAngle >= 45 && relativeMouseAngle < 135) snappedAngle = 180 - inputAngleDegrees;
|
||||||
|
else if (relativeMouseAngle >= 135 || relativeMouseAngle < -135) snappedAngle = inputAngleDegrees + 180.0;
|
||||||
|
else snappedAngle = 360 - inputAngleDegrees;
|
||||||
|
double finalAngleRad = qDegreesToRadians(refAngle + snappedAngle);
|
||||||
|
QVector3D finalDir;
|
||||||
|
if (m_currentPlane == SketchPlane::XY) finalDir = QVector3D(cos(finalAngleRad), 0, sin(finalAngleRad));
|
||||||
|
else if (m_currentPlane == SketchPlane::XZ) finalDir = QVector3D(cos(finalAngleRad), sin(finalAngleRad), 0);
|
||||||
|
else finalDir = QVector3D(0, cos(finalAngleRad), sin(finalAngleRad));
|
||||||
|
double lineLength;
|
||||||
|
if (lengthFromInput) lineLength = inputLength;
|
||||||
|
else {
|
||||||
|
lineLength = QVector3D::dotProduct(mouseVec, finalDir);
|
||||||
|
if (lineLength < 0) lineLength = 0;
|
||||||
|
}
|
||||||
|
worldPos = startPos + lineLength * finalDir;
|
||||||
|
} else if (lengthFromInput) {
|
||||||
|
QVector3D currentMouseWorldPos = unproject(m_currentMousePos, m_currentPlane);
|
||||||
|
QVector3D dir = (currentMouseWorldPos - startPos);
|
||||||
|
if (dir.length() > 1e-6) {
|
||||||
|
dir.normalize();
|
||||||
|
worldPos = startPos + inputLength * dir;
|
||||||
|
} else {
|
||||||
|
if (m_currentPlane == SketchPlane::XY || m_currentPlane == SketchPlane::XZ) worldPos = startPos + QVector3D(inputLength, 0, 0);
|
||||||
|
else worldPos = startPos + QVector3D(0, inputLength, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
worldPos = unproject(m_currentMousePos, m_currentPlane);
|
||||||
|
}
|
||||||
|
|
||||||
|
gp_Pnt p;
|
||||||
|
p.SetCoord(worldPos.x(), worldPos.y(), worldPos.z());
|
||||||
|
|
||||||
|
QVector3D prevDir = (worldPos - startPos).normalized();
|
||||||
|
setProperty("previousLineDirection", QVariant::fromValue(prevDir));
|
||||||
|
|
||||||
|
emit lineAdded(m_firstLinePoint, p);
|
||||||
|
m_firstLinePoint = p;
|
||||||
|
setProperty("dimensionInput", QVariant(""));
|
||||||
|
setProperty("angleInput", QVariant(""));
|
||||||
|
setProperty("dimensionEditMode", "length");
|
||||||
|
setProperty("isChainedLine", true);
|
||||||
|
update();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (event->key() == Qt::Key_Escape) {
|
if (event->key() == Qt::Key_Escape) {
|
||||||
if (m_isDefiningLine) {
|
if (m_isDefiningLine) {
|
||||||
m_isDefiningLine = false;
|
m_isDefiningLine = false;
|
||||||
|
setProperty("dimensionInput", QVariant(""));
|
||||||
|
setProperty("angleInput", QVariant(""));
|
||||||
emit toolDeactivated();
|
emit toolDeactivated();
|
||||||
update();
|
update();
|
||||||
return;
|
return;
|
||||||
@@ -480,6 +1054,14 @@ void ViewportWidget::keyPressEvent(QKeyEvent *event)
|
|||||||
QOpenGLWidget::keyPressEvent(event);
|
QOpenGLWidget::keyPressEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ViewportWidget::focusNextPrevChild(bool next)
|
||||||
|
{
|
||||||
|
if (m_activeTool != static_cast<int>(ApplicationController::ToolType::None)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return QOpenGLWidget::focusNextPrevChild(next);
|
||||||
|
}
|
||||||
|
|
||||||
void ViewportWidget::onSketchModeStarted(SketchPlane plane)
|
void ViewportWidget::onSketchModeStarted(SketchPlane plane)
|
||||||
{
|
{
|
||||||
m_currentPlane = plane;
|
m_currentPlane = plane;
|
||||||
@@ -744,10 +1326,9 @@ void ViewportWidget::drawSketch(const SketchFeature* sketch)
|
|||||||
{
|
{
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glLineWidth(2.0f);
|
glLineWidth(2.0f);
|
||||||
glPointSize(5.0f);
|
|
||||||
|
|
||||||
QVector<GLfloat> lineVertices;
|
QVector<GLfloat> lineVertices;
|
||||||
QMap<gp_Pnt, int, PntComparator> vertexCounts;
|
std::map<gp_Pnt, int, PntComparator> vertexCounts;
|
||||||
|
|
||||||
for (const auto& obj : sketch->objects()) {
|
for (const auto& obj : sketch->objects()) {
|
||||||
if (obj->type() == SketchObject::ObjectType::Line) {
|
if (obj->type() == SketchObject::ObjectType::Line) {
|
||||||
@@ -762,14 +1343,6 @@ void ViewportWidget::drawSketch(const SketchFeature* sketch)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<GLfloat> pointVertices;
|
|
||||||
for (auto it = vertexCounts.constBegin(); it != vertexCounts.constEnd(); ++it) {
|
|
||||||
if (it.value() == 1) {
|
|
||||||
const gp_Pnt& p = it.key();
|
|
||||||
pointVertices << p.X() << p.Y() << p.Z();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_shaderProgram->setUniformValue(m_colorLoc, QVector4D(1.0f, 1.0f, 1.0f, 1.0f));
|
m_shaderProgram->setUniformValue(m_colorLoc, QVector4D(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
m_vbo.bind();
|
m_vbo.bind();
|
||||||
|
|
||||||
@@ -777,14 +1350,57 @@ void ViewportWidget::drawSketch(const SketchFeature* sketch)
|
|||||||
m_vbo.allocate(lineVertices.constData(), lineVertices.size() * sizeof(GLfloat));
|
m_vbo.allocate(lineVertices.constData(), lineVertices.size() * sizeof(GLfloat));
|
||||||
glDrawArrays(GL_LINES, 0, lineVertices.size() / 3);
|
glDrawArrays(GL_LINES, 0, lineVertices.size() / 3);
|
||||||
}
|
}
|
||||||
if (!pointVertices.isEmpty()) {
|
|
||||||
glEnable(GL_POINT_SMOOTH);
|
QVector<gp_Pnt> unattachedVertices;
|
||||||
glEnable(GL_BLEND);
|
for (const auto& pair : vertexCounts) {
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
if (pair.second == 1) {
|
||||||
m_vbo.allocate(pointVertices.constData(), pointVertices.size() * sizeof(GLfloat));
|
unattachedVertices.append(pair.first);
|
||||||
glDrawArrays(GL_POINTS, 0, pointVertices.size() / 3);
|
}
|
||||||
glDisable(GL_BLEND);
|
}
|
||||||
glDisable(GL_POINT_SMOOTH);
|
|
||||||
|
if (!unattachedVertices.isEmpty()) {
|
||||||
|
const float radius = 0.004f * -m_camera->zoom();
|
||||||
|
const int numSegments = 16;
|
||||||
|
QMatrix4x4 invModelView = m_camera->modelViewMatrix().inverted();
|
||||||
|
QVector3D rightVec = invModelView.column(0).toVector3D();
|
||||||
|
QVector3D upVec = invModelView.column(1).toVector3D();
|
||||||
|
|
||||||
|
QVector<GLfloat> circleFillVertices;
|
||||||
|
QVector<GLfloat> circleOutlineVertices;
|
||||||
|
|
||||||
|
for (const auto& centerPnt : unattachedVertices) {
|
||||||
|
QVector3D center(centerPnt.X(), centerPnt.Y(), centerPnt.Z());
|
||||||
|
|
||||||
|
circleFillVertices << center.x() << center.y() << center.z(); // Center vertex for fan
|
||||||
|
|
||||||
|
QVector3D firstCircumferencePoint;
|
||||||
|
for (int i = 0; i < numSegments; ++i) {
|
||||||
|
float angle = (2.0f * M_PI * float(i)) / float(numSegments);
|
||||||
|
QVector3D p = center + radius * (cos(angle) * rightVec + sin(angle) * upVec);
|
||||||
|
if (i == 0) {
|
||||||
|
firstCircumferencePoint = p;
|
||||||
|
}
|
||||||
|
circleFillVertices << p.x() << p.y() << p.z();
|
||||||
|
circleOutlineVertices << p.x() << p.y() << p.z();
|
||||||
|
}
|
||||||
|
circleFillVertices << firstCircumferencePoint.x() << firstCircumferencePoint.y() << firstCircumferencePoint.z();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw fills
|
||||||
|
m_shaderProgram->setUniformValue(m_colorLoc, QVector4D(0.2f, 0.3f, 0.3f, 1.0f));
|
||||||
|
m_vbo.allocate(circleFillVertices.constData(), circleFillVertices.size() * sizeof(GLfloat));
|
||||||
|
const int vertsPerFan = numSegments + 2;
|
||||||
|
for (size_t i = 0; i < unattachedVertices.size(); ++i) {
|
||||||
|
glDrawArrays(GL_TRIANGLE_FAN, i * vertsPerFan, vertsPerFan);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw outlines
|
||||||
|
m_shaderProgram->setUniformValue(m_colorLoc, QVector4D(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
|
m_vbo.allocate(circleOutlineVertices.constData(), circleOutlineVertices.size() * sizeof(GLfloat));
|
||||||
|
const int vertsPerLoop = numSegments;
|
||||||
|
for (size_t i = 0; i < unattachedVertices.size(); ++i) {
|
||||||
|
glDrawArrays(GL_LINE_LOOP, i * vertsPerLoop, vertsPerLoop);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ protected:
|
|||||||
void mouseMoveEvent(QMouseEvent *event) override;
|
void mouseMoveEvent(QMouseEvent *event) override;
|
||||||
void wheelEvent(QWheelEvent *event) override;
|
void wheelEvent(QWheelEvent *event) override;
|
||||||
void keyPressEvent(QKeyEvent *event) override;
|
void keyPressEvent(QKeyEvent *event) override;
|
||||||
|
bool focusNextPrevChild(bool next) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initShaders();
|
void initShaders();
|
||||||
|
|||||||
Reference in New Issue
Block a user