From 127ee90cec23201dd168442b1fefb24bdbf34d9e Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Mon, 29 Apr 2024 12:19:04 +0200 Subject: [PATCH] TechDraw: Enable snapping section views to their base views. --- src/Mod/TechDraw/App/DrawViewSection.cpp | 28 ++++---- src/Mod/TechDraw/App/DrawViewSection.h | 1 + src/Mod/TechDraw/Gui/QGIView.cpp | 67 ++++++++++++++++--- src/Mod/TechDraw/Gui/QGIView.h | 2 + .../TechDraw/Gui/ViewProviderDrawingView.cpp | 2 +- 5 files changed, 77 insertions(+), 23 deletions(-) diff --git a/src/Mod/TechDraw/App/DrawViewSection.cpp b/src/Mod/TechDraw/App/DrawViewSection.cpp index 1b9a53695b..f90aa57582 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.cpp +++ b/src/Mod/TechDraw/App/DrawViewSection.cpp @@ -932,27 +932,29 @@ std::vector DrawViewSection::makeTDSectionFaces(TopoDS_Compou std::pair DrawViewSection::sectionLineEnds() { std::pair result; - Base::Vector3d stdZ(0.0, 0.0, 1.0); - double baseRotation = getBaseDVP()->Rotation.getValue();// Qt degrees are clockwise - Base::Rotation rotator(stdZ, baseRotation * M_PI / 180.0); - Base::Rotation unrotator(stdZ, -baseRotation * M_PI / 180.0); + Base::Vector3d dir = getSectionDirectionOnBaseView(); + + Base::Vector3d sectionOrg = SectionOrigin.getValue() - getBaseDVP()->getOriginalCentroid(); + sectionOrg = getBaseDVP()->projectPoint(sectionOrg);// convert to base view CS + double halfSize = (getBaseDVP()->getSizeAlongVector(dir) / 2.0) * SectionLineStretch.getValue(); + result.first = sectionOrg + dir * halfSize; + result.second = sectionOrg - dir * halfSize; + + return result; +} + +// calculate the direction of the section in 2d on the base view. +Base::Vector3d DrawViewSection::getSectionDirectionOnBaseView() +{ auto sNorm = SectionNormal.getValue(); auto axis = getBaseDVP()->Direction.getValue(); - Base::Vector3d stdOrg(0.0, 0.0, 0.0); Base::Vector3d sectionLineDir = -axis.Cross(sNorm); sectionLineDir.Normalize(); sectionLineDir = getBaseDVP()->projectPoint(sectionLineDir);// convert to base view CS sectionLineDir.Normalize(); - Base::Vector3d sectionOrg = SectionOrigin.getValue() - getBaseDVP()->getOriginalCentroid(); - sectionOrg = getBaseDVP()->projectPoint(sectionOrg);// convert to base view - // CS - double halfSize = (getBaseDVP()->getSizeAlongVector(sectionLineDir) / 2.0) * SectionLineStretch.getValue(); - result.first = sectionOrg + sectionLineDir * halfSize; - result.second = sectionOrg - sectionLineDir * halfSize; - - return result; + return sectionLineDir; } // find the points and directions to make the change point marks. diff --git a/src/Mod/TechDraw/App/DrawViewSection.h b/src/Mod/TechDraw/App/DrawViewSection.h index ed311fe27b..eddad34073 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.h +++ b/src/Mod/TechDraw/App/DrawViewSection.h @@ -165,6 +165,7 @@ public: static const char* CutSurfaceEnums[]; virtual std::pair sectionLineEnds(); + Base::Vector3d getSectionDirectionOnBaseView(); virtual ChangePointVector getChangePointsFromSectionLine(); bool showSectionEdges(void); diff --git a/src/Mod/TechDraw/Gui/QGIView.cpp b/src/Mod/TechDraw/Gui/QGIView.cpp index 620900380d..760068c61f 100644 --- a/src/Mod/TechDraw/Gui/QGIView.cpp +++ b/src/Mod/TechDraw/Gui/QGIView.cpp @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include #include @@ -71,7 +73,8 @@ QGIView::QGIView() :QGraphicsItemGroup(), viewObj(nullptr), m_innerView(false), - m_multiselectActivated(false) + m_multiselectActivated(false), + snapping(false) { setCacheMode(QGraphicsItem::NoCache); setHandlesChildEvents(false); @@ -153,10 +156,9 @@ void QGIView::alignTo(QGraphicsItem*item, const QString &alignment) QVariant QGIView::itemChange(GraphicsItemChange change, const QVariant &value) { - QPointF newPos(0.0, 0.0); // Base::Console().Message("QGIV::itemChange(%d)\n", change); if(change == ItemPositionChange && scene()) { - newPos = value.toPointF(); //position within parent! + QPointF newPos = value.toPointF(); //position within parent! TechDraw::DrawView *viewObj = getViewObject(); auto* dpgi = dynamic_cast(viewObj); @@ -181,7 +183,9 @@ QVariant QGIView::itemChange(GraphicsItemChange change, const QVariant &value) // tell the feature that we have moved Gui::ViewProvider *vp = getViewProvider(viewObj); if (vp && !vp->isRestoring()) { + snapping = true; // avoid triggering updateView by the VP updateData viewObj->setPosition(Rez::appX(newPos.x()), Rez::appX(-newPos.y())); + snapping = false; } return newPos; @@ -201,7 +205,7 @@ QVariant QGIView::itemChange(GraphicsItemChange change, const QVariant &value) return QGraphicsItemGroup::itemChange(change, value); } -void QGIView::snapPosition(QPointF& pos) +void QGIView::snapPosition(QPointF& mPos) { // For general views we check if the view is close to aligned vertically or horizontally to another view. @@ -220,20 +224,65 @@ void QGIView::snapPosition(QPointF& pos) } std::vector views = scenePage->getViews(); - qreal snapPercent = 0.05; + + auto* sectionView = dynamic_cast(getViewObject()); + if (sectionView) { + auto* baseView = sectionView->getBaseDVP(); + if (!baseView) { return; } + + Base::Vector3d dir3d = sectionView->getSectionDirectionOnBaseView(); + double bSize = Rez::guiX(baseView->getSizeAlongVector(dir3d)); + double sSize = Rez::guiX(sectionView->getSizeAlongVector(dir3d)); + + auto* vpdv = dynamic_cast(getViewProvider(baseView)); + if (!vpdv) { return; } + auto* qgiv(dynamic_cast(vpdv->getQView())); + if (!qgiv) { return; } + QPointF bvPos = qgiv->pos(); + Base::Vector2d bvPt(bvPos.x(), bvPos.y()); + Base::Vector2d mPt(mPos.x(), mPos.y()); + Base::Vector2d dir(dir3d.x, dir3d.y); + if (dir.Length() < Precision::Confusion()) { return; } + dir.Normalize(); + + double snapDist = bSize * snapPercent; + + Base::Vector2d projPt; + projPt.ProjectToLine(mPt - bvPt, dir); + projPt = projPt + bvPt; + + Base::Vector2d v = (projPt - bvPt) + 0.5 * (sSize - bSize) * dir; + int sign = v * dir > 0 ? - 1 : 1; + double dist = v.Length(); + if (dist < snapDist) { + v = dist * dir; + mPos = mPos + sign * QPointF(v.x, v.y); + return; + } + + v = (projPt - bvPt) + 0.5 * (bSize - sSize) * dir; + sign = v * dir > 0 ? - 1 : 1; + dist = v.Length(); + if (dist < snapDist) { + v = dist * dir; + mPos = mPos + sign * QPointF(v.x, v.y); + return; + } + } + for (auto* view : views) { if (view == this) { continue; } QPointF vPos = view->pos(); qreal dx = view->boundingRect().width() * snapPercent; qreal dy = view->boundingRect().height() * snapPercent; - if (fabs(pos.x() - vPos.x()) < dx) { - pos.setX(vPos.x()); + if (fabs(mPos.x() - vPos.x()) < dx) { + mPos.setX(vPos.x()); break; } - else if (fabs(pos.y() - vPos.y()) < dy) { - pos.setY(vPos.y()); + else if (fabs(mPos.y() - vPos.y()) < dy) { + mPos.setY(vPos.y()); break; } } diff --git a/src/Mod/TechDraw/Gui/QGIView.h b/src/Mod/TechDraw/Gui/QGIView.h index 44428dd479..b1ce7c0f04 100644 --- a/src/Mod/TechDraw/Gui/QGIView.h +++ b/src/Mod/TechDraw/Gui/QGIView.h @@ -122,6 +122,7 @@ public: void isInnerView(bool state) { m_innerView = state; } QGIViewClip* getClipGroup(); + bool isSnapping() { return snapping; } void snapPosition(QPointF& position); void alignTo(QGraphicsItem*, const QString &alignment); @@ -182,6 +183,7 @@ private: QHash alignHash; bool m_innerView; //View is inside another View bool m_multiselectActivated; + bool snapping; QPen m_pen; QBrush m_brush; diff --git a/src/Mod/TechDraw/Gui/ViewProviderDrawingView.cpp b/src/Mod/TechDraw/Gui/ViewProviderDrawingView.cpp index fc9fd107e5..b7b1c801ce 100644 --- a/src/Mod/TechDraw/Gui/ViewProviderDrawingView.cpp +++ b/src/Mod/TechDraw/Gui/ViewProviderDrawingView.cpp @@ -227,7 +227,7 @@ void ViewProviderDrawingView::updateData(const App::Property* prop) if (prop == &obj->X || prop == &obj->Y) { QGIView* qgiv = getQView(); - if (qgiv) { + if (qgiv && !qgiv->isSnapping()) { qgiv->QGIView::updateView(true); // Update also the owner/parent view, if there is any