refactor: Extract snapping logic into dedicated Snapping class

Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
2026-02-17 11:19:29 -07:00
parent e86a775b46
commit d708ab9827
4 changed files with 241 additions and 169 deletions

View File

@@ -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<int>(ApplicationController::ToolType::Line), new LineTool(this));
m_sketchTools.insert(static_cast<int>(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<GLfloat> 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<int>(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<int>(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<SketchFeature*>(feature)) {
for (const auto& obj : sketch->objects()) {
if (obj->type() == SketchObject::ObjectType::Line) {
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_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<const SketchRectangle*>(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;