diff --git a/src/Snapping.cpp b/src/Snapping.cpp index e69de29..c1f1af2 100644 --- a/src/Snapping.cpp +++ b/src/Snapping.cpp @@ -0,0 +1,185 @@ +#include "Snapping.h" + +#include "ViewportWidget.h" +#include "Camera.h" +#include "Document.h" +#include "SketchFeature.h" +#include "SketchLine.h" +#include "SketchRectangle.h" +#include "SketchObject.h" +#include "ApplicationController.h" + +#include +#include +#include + +Snapping::Snapping(ViewportWidget* viewport) : m_viewport(viewport) +{ +} + +bool Snapping::update(const QPoint& mousePos) +{ + bool oldIsSnappingOrigin = m_isSnappingOrigin; + bool oldIsSnappingVertex = m_isSnappingVertex; + + bool shouldSnap = false; + if (m_viewport->currentPlane() != ViewportWidget::SketchPlane::NONE && m_viewport->activeTool() != static_cast(ApplicationController::ToolType::None)) { + QVector3D worldPos = m_viewport->unproject(mousePos, m_viewport->currentPlane()); + const float snapRectHalfSize = 0.0075f * -m_viewport->camera()->zoom(); + + switch (m_viewport->currentPlane()) { + case ViewportWidget::SketchPlane::XY: + shouldSnap = qAbs(worldPos.x()) < snapRectHalfSize && qAbs(worldPos.z()) < snapRectHalfSize; + break; + case ViewportWidget::SketchPlane::XZ: + shouldSnap = qAbs(worldPos.x()) < snapRectHalfSize && qAbs(worldPos.y()) < snapRectHalfSize; + break; + case ViewportWidget::SketchPlane::YZ: + shouldSnap = qAbs(worldPos.y()) < snapRectHalfSize && qAbs(worldPos.z()) < snapRectHalfSize; + break; + case ViewportWidget::SketchPlane::NONE: + break; + } + } + + m_isSnappingOrigin = shouldSnap; + if (m_isSnappingOrigin) { + m_isSnappingVertex = false; + } + + m_isSnappingVertex = false; + if (!m_isSnappingOrigin && m_viewport->document() && m_viewport->currentPlane() != ViewportWidget::SketchPlane::NONE && m_viewport->activeTool() != static_cast(ApplicationController::ToolType::None)) { + QVector3D worldPos = m_viewport->unproject(mousePos, m_viewport->currentPlane()); + const float snapRectHalfSize = 0.0075f * -m_viewport->camera()->zoom(); + + for (Feature* feature : m_viewport->document()->features()) { + if (auto sketch = dynamic_cast(feature)) { + for (const auto& obj : sketch->objects()) { + if (obj->type() == SketchObject::ObjectType::Line) { + auto line = static_cast(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.z() - vertex.Z()) < snapRectHalfSize; + break; + case ViewportWidget::SketchPlane::XZ: + isClose = qAbs(worldPos.x() - vertex.X()) < snapRectHalfSize && qAbs(worldPos.y() - vertex.Y()) < snapRectHalfSize; + break; + case ViewportWidget::SketchPlane::YZ: + isClose = qAbs(worldPos.y() - vertex.Y()) < snapRectHalfSize && qAbs(worldPos.z() - vertex.Z()) < snapRectHalfSize; + break; + case ViewportWidget::SketchPlane::NONE: + break; + } + + if (isClose) { + m_isSnappingVertex = true; + m_snapVertex = vertex; + goto end_snap_check; + } + } + } else if (obj->type() == SketchObject::ObjectType::Rectangle) { + auto rect = static_cast(obj); + 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(), p1.Y(), p3.Z()); + } else if (sketch->plane() == SketchFeature::SketchPlane::XZ) { + p2.SetCoord(p3.X(), p1.Y(), p1.Z()); + p4.SetCoord(p1.X(), p3.Y(), p1.Z()); + } else if (sketch->plane() == SketchFeature::SketchPlane::YZ) { + p2.SetCoord(p1.X(), p3.Y(), p1.Z()); + p4.SetCoord(p1.X(), p1.Y(), p3.Z()); + } + + 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.z() - vertex.Z()) < snapRectHalfSize; + break; + case ViewportWidget::SketchPlane::XZ: + isClose = qAbs(worldPos.x() - vertex.X()) < snapRectHalfSize && qAbs(worldPos.y() - vertex.Y()) < snapRectHalfSize; + break; + case ViewportWidget::SketchPlane::YZ: + isClose = qAbs(worldPos.y() - vertex.Y()) < snapRectHalfSize && qAbs(worldPos.z() - vertex.Z()) < snapRectHalfSize; + break; + case ViewportWidget::SketchPlane::NONE: + break; + } + + if (isClose) { + m_isSnappingVertex = true; + m_snapVertex = vertex; + goto end_snap_check; + } + } + } + } + } + } + end_snap_check:; + } + + return (oldIsSnappingOrigin != m_isSnappingOrigin) || (oldIsSnappingVertex != m_isSnappingVertex); +} + +void Snapping::paintGL() const +{ + if (!m_isSnappingOrigin && !m_isSnappingVertex) { + return; + } + + QVector vertices; + if (m_isSnappingOrigin) { + const float rectSize = 0.0075f * -m_viewport->camera()->zoom(); + if (m_viewport->currentPlane() == ViewportWidget::SketchPlane::XY) { + 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::XZ) { + 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::YZ) { + vertices << 0 << -rectSize << -rectSize << 0 << rectSize << -rectSize; + vertices << 0 << rectSize << -rectSize << 0 << rectSize << rectSize; + vertices << 0 << rectSize << rectSize << 0 << -rectSize << rectSize; + vertices << 0 << -rectSize << rectSize << 0 << -rectSize << -rectSize; + } + } else if (m_isSnappingVertex) { + 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() << 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::XZ) { + 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::YZ) { + vertices << v.X() << v.Y() - rectSize << v.Z() - rectSize << v.X() << v.Y() + rectSize << v.Z() - rectSize; + vertices << v.X() << v.Y() + rectSize << v.Z() - rectSize << v.X() << v.Y() + rectSize << v.Z() + rectSize; + vertices << v.X() << v.Y() + rectSize << v.Z() + rectSize << v.X() << v.Y() - rectSize << v.Z() + rectSize; + vertices << v.X() << v.Y() - rectSize << v.Z() + rectSize << v.X() << v.Y() - rectSize << v.Z() - rectSize; + } + } + m_viewport->shaderProgram()->setUniformValue(m_viewport->colorLoc(), QVector4D(1.0f, 1.0f, 0.0f, 0.5f)); + m_viewport->vbo().bind(); + m_viewport->vbo().allocate(vertices.constData(), vertices.size() * sizeof(GLfloat)); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDrawArrays(GL_LINES, 0, vertices.size() / 3); + glDisable(GL_BLEND); +} diff --git a/src/Snapping.h b/src/Snapping.h index e69de29..ff6b4ae 100644 --- a/src/Snapping.h +++ b/src/Snapping.h @@ -0,0 +1,28 @@ +#ifndef SNAPPING_H +#define SNAPPING_H + +#include +#include + +class ViewportWidget; + +class Snapping +{ +public: + explicit Snapping(ViewportWidget* viewport); + + bool update(const QPoint& mousePos); + void paintGL() const; + + bool isSnappingOrigin() const { return m_isSnappingOrigin; } + bool isSnappingVertex() const { return m_isSnappingVertex; } + const gp_Pnt& snapVertex() const { return m_snapVertex; } + +private: + ViewportWidget* m_viewport = nullptr; + bool m_isSnappingOrigin = false; + bool m_isSnappingVertex = false; + gp_Pnt m_snapVertex; +}; + +#endif // SNAPPING_H diff --git a/src/ViewportWidget.cpp b/src/ViewportWidget.cpp index cde75be..99a87c2 100644 --- a/src/ViewportWidget.cpp +++ b/src/ViewportWidget.cpp @@ -1,4 +1,5 @@ #include "ViewportWidget.h" +#include "Snapping.h" #include "Camera.h" #include "ViewCube.h" #include "SketchGrid.h" @@ -61,6 +62,8 @@ ViewportWidget::ViewportWidget(QWidget *parent) m_sketchTools.insert(static_cast(ApplicationController::ToolType::Line), new LineTool(this)); m_sketchTools.insert(static_cast(ApplicationController::ToolType::Rectangle), new RectangleTool(this)); + + m_snapping = new Snapping(this); } ViewportWidget::~ViewportWidget() @@ -74,6 +77,7 @@ ViewportWidget::~ViewportWidget() doneCurrent(); delete m_featureBrowser; + delete m_snapping; } void ViewportWidget::setDocument(Document* document) @@ -148,59 +152,7 @@ void ViewportWidget::paintGL() } } - QVector vertices; - if (m_isSnappingOrigin) { - const float rectSize = 0.0075f * -m_camera->zoom(); - if (m_currentPlane == SketchPlane::XY) { - 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_currentPlane == SketchPlane::XZ) { - 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_currentPlane == 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; - } - m_shaderProgram->setUniformValue(m_colorLoc, QVector4D(1.0f, 1.0f, 0.0f, 0.5f)); - m_vbo.bind(); - m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat)); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDrawArrays(GL_LINES, 0, vertices.size() / 3); - glDisable(GL_BLEND); - } else if (m_isSnappingVertex) { - const float rectSize = 0.0075f * -m_camera->zoom(); - const auto& v = m_snapVertex; - if (m_currentPlane == SketchPlane::XY) { - 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_currentPlane == SketchPlane::XZ) { - 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_currentPlane == SketchPlane::YZ) { - vertices << v.X() << v.Y() - rectSize << v.Z() - rectSize << v.X() << v.Y() + rectSize << v.Z() - rectSize; - vertices << v.X() << v.Y() + rectSize << v.Z() - rectSize << v.X() << v.Y() + rectSize << v.Z() + rectSize; - vertices << v.X() << v.Y() + rectSize << v.Z() + rectSize << v.X() << v.Y() - rectSize << v.Z() + rectSize; - vertices << v.X() << v.Y() - rectSize << v.Z() + rectSize << v.X() << v.Y() - rectSize << v.Z() - rectSize; - } - m_shaderProgram->setUniformValue(m_colorLoc, QVector4D(1.0f, 1.0f, 0.0f, 0.5f)); - m_vbo.bind(); - m_vbo.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat)); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDrawArrays(GL_LINES, 0, vertices.size() / 3); - glDisable(GL_BLEND); - } + m_snapping->paintGL(); if (m_activeSketchTool) { m_activeSketchTool->paintGL(); @@ -274,116 +226,7 @@ void ViewportWidget::mouseMoveEvent(QMouseEvent *event) } } - bool shouldSnap = false; - if (m_currentPlane != SketchPlane::NONE && m_activeTool != static_cast(ApplicationController::ToolType::None)) { - QVector3D worldPos = unproject(m_currentMousePos, m_currentPlane); - const float snapRectHalfSize = 0.0075f * -m_camera->zoom(); - - switch (m_currentPlane) { - case SketchPlane::XY: - shouldSnap = qAbs(worldPos.x()) < snapRectHalfSize && qAbs(worldPos.z()) < snapRectHalfSize; - break; - case SketchPlane::XZ: - shouldSnap = qAbs(worldPos.x()) < snapRectHalfSize && qAbs(worldPos.y()) < snapRectHalfSize; - break; - case SketchPlane::YZ: - shouldSnap = qAbs(worldPos.y()) < snapRectHalfSize && qAbs(worldPos.z()) < snapRectHalfSize; - break; - case SketchPlane::NONE: - break; - } - } - - if (shouldSnap != m_isSnappingOrigin) { - m_isSnappingOrigin = shouldSnap; - if (m_isSnappingOrigin) { - m_isSnappingVertex = false; - } - update(); - } - - bool oldIsSnappingVertex = m_isSnappingVertex; - m_isSnappingVertex = false; - if (!m_isSnappingOrigin && m_document && m_currentPlane != SketchPlane::NONE && m_activeTool != static_cast(ApplicationController::ToolType::None)) { - QVector3D worldPos = unproject(m_currentMousePos, m_currentPlane); - const float snapRectHalfSize = 0.0075f * -m_camera->zoom(); - - for (Feature* feature : m_document->features()) { - if (auto sketch = dynamic_cast(feature)) { - for (const auto& obj : sketch->objects()) { - if (obj->type() == SketchObject::ObjectType::Line) { - auto line = static_cast(obj); - const gp_Pnt vertices[] = {line->startPoint(), line->endPoint()}; - for (const auto& vertex : vertices) { - bool isClose = false; - switch (m_currentPlane) { - case SketchPlane::XY: - isClose = qAbs(worldPos.x() - vertex.X()) < snapRectHalfSize && qAbs(worldPos.z() - vertex.Z()) < snapRectHalfSize; - break; - case SketchPlane::XZ: - isClose = qAbs(worldPos.x() - vertex.X()) < snapRectHalfSize && qAbs(worldPos.y() - vertex.Y()) < snapRectHalfSize; - break; - case SketchPlane::YZ: - isClose = qAbs(worldPos.y() - vertex.Y()) < snapRectHalfSize && qAbs(worldPos.z() - vertex.Z()) < snapRectHalfSize; - break; - case SketchPlane::NONE: - break; - } - - if (isClose) { - m_isSnappingVertex = true; - m_snapVertex = vertex; - goto end_snap_check; - } - } - } else if (obj->type() == SketchObject::ObjectType::Rectangle) { - auto rect = static_cast(obj); - 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(), p1.Y(), p3.Z()); - } else if (sketch->plane() == SketchFeature::SketchPlane::XZ) { - p2.SetCoord(p3.X(), p1.Y(), p1.Z()); - p4.SetCoord(p1.X(), p3.Y(), p1.Z()); - } else if (sketch->plane() == SketchFeature::SketchPlane::YZ) { - p2.SetCoord(p1.X(), p3.Y(), p1.Z()); - p4.SetCoord(p1.X(), p1.Y(), p3.Z()); - } - - const gp_Pnt vertices[] = {p1, p2, p3, p4}; - for (const auto& vertex : vertices) { - bool isClose = false; - switch (m_currentPlane) { - case SketchPlane::XY: - isClose = qAbs(worldPos.x() - vertex.X()) < snapRectHalfSize && qAbs(worldPos.z() - vertex.Z()) < snapRectHalfSize; - break; - case SketchPlane::XZ: - isClose = qAbs(worldPos.x() - vertex.X()) < snapRectHalfSize && qAbs(worldPos.y() - vertex.Y()) < snapRectHalfSize; - break; - case SketchPlane::YZ: - isClose = qAbs(worldPos.y() - vertex.Y()) < snapRectHalfSize && qAbs(worldPos.z() - vertex.Z()) < snapRectHalfSize; - break; - case SketchPlane::NONE: - break; - } - - if (isClose) { - m_isSnappingVertex = true; - m_snapVertex = vertex; - goto end_snap_check; - } - } - } - } - } - } - end_snap_check:; - } - - if (oldIsSnappingVertex != m_isSnappingVertex) { + if (m_snapping->update(m_currentMousePos)) { update(); } @@ -437,6 +280,21 @@ void ViewportWidget::deactivateActiveTool() emit toolDeactivated(); } +bool ViewportWidget::isSnappingOrigin() const +{ + return m_snapping->isSnappingOrigin(); +} + +bool ViewportWidget::isSnappingVertex() const +{ + return m_snapping->isSnappingVertex(); +} + +const gp_Pnt& ViewportWidget::snapVertex() const +{ + return m_snapping->snapVertex(); +} + void ViewportWidget::setSnappingHorizontal(bool snapping) { m_isSnappingHorizontal = snapping; diff --git a/src/ViewportWidget.h b/src/ViewportWidget.h index 900082f..e20ec6e 100644 --- a/src/ViewportWidget.h +++ b/src/ViewportWidget.h @@ -21,6 +21,7 @@ class FeatureBrowser; class SketchFeature; class Camera; class SketchTool; +class Snapping; class ViewportWidget : public QOpenGLWidget, protected QOpenGLFunctions { @@ -45,11 +46,13 @@ public: 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; } const QPoint& currentMousePos() const { return m_currentMousePos; } - bool isSnappingOrigin() const { return m_isSnappingOrigin; } - bool isSnappingVertex() const { return m_isSnappingVertex; } - const gp_Pnt& snapVertex() const { return m_snapVertex; } + bool isSnappingOrigin() const; + bool isSnappingVertex() const; + const gp_Pnt& snapVertex() const; + int activeTool() const { return m_activeTool; } bool isSnappingHorizontal() const { return m_isSnappingHorizontal; } bool isSnappingVertical() const { return m_isSnappingVertical; } void setSnappingHorizontal(bool snapping); @@ -111,9 +114,7 @@ private: SketchTool* m_activeSketchTool = nullptr; QMap m_sketchTools; QPoint m_currentMousePos; - bool m_isSnappingOrigin = false; - bool m_isSnappingVertex = false; - gp_Pnt m_snapVertex; + Snapping* m_snapping = nullptr; bool m_isSnappingHorizontal = false; bool m_isSnappingVertical = false;