From 140bcf605e6ef21fe0c827233cdea82d6ddab7b4 Mon Sep 17 00:00:00 2001 From: WandererFan Date: Mon, 2 Sep 2024 12:41:25 -0400 Subject: [PATCH] [TD]Fix section snapping (fix #15961) (#15450) * [TD]Add view snapping preferences * [TD]fix section snapping algo - snap sections to section normal line. - snap views to other views in X&Y * [TD]fix snapping to ProjectionGroups --- src/Mod/TechDraw/App/DrawUtil.cpp | 31 ++ src/Mod/TechDraw/App/DrawUtil.h | 3 + src/Mod/TechDraw/App/DrawView.cpp | 19 +- src/Mod/TechDraw/App/DrawView.h | 4 +- src/Mod/TechDraw/App/DrawViewSection.cpp | 19 +- src/Mod/TechDraw/App/DrawViewSection.h | 3 +- src/Mod/TechDraw/App/Preferences.cpp | 13 + src/Mod/TechDraw/App/Preferences.h | 3 + .../TechDraw/Gui/DlgPrefsTechDrawGeneral.ui | 104 +++++- .../Gui/DlgPrefsTechDrawGeneralImp.cpp | 5 + src/Mod/TechDraw/Gui/QGIView.cpp | 311 ++++++++++++------ src/Mod/TechDraw/Gui/QGIView.h | 8 +- 12 files changed, 404 insertions(+), 119 deletions(-) diff --git a/src/Mod/TechDraw/App/DrawUtil.cpp b/src/Mod/TechDraw/App/DrawUtil.cpp index c20de049ea..ed9a047200 100644 --- a/src/Mod/TechDraw/App/DrawUtil.cpp +++ b/src/Mod/TechDraw/App/DrawUtil.cpp @@ -271,6 +271,37 @@ double DrawUtil::incidenceAngleAtVertex(TopoDS_Edge e, TopoDS_Vertex v, double t return incidenceAngle; } + +//! true if actualAngle(degrees) is within allowableError [0,360] of +//! targetAngle (degrees) +bool DrawUtil::isWithinRange(double actualAngleIn, double targetAngleIn, double allowableError) +{ + constexpr double DegreesPerRevolution{360}; + constexpr double DegreesPerHalfRevolution{180}; + // map both angles from [0, 360] to [-180, 180]. This solves the problem of + // comparing angles near 0, such as 5deg & 355deg where the desired answer is + // 10, not 350; + double actualAngleDeg = actualAngleIn; + if (actualAngleDeg < DegreesPerRevolution && + actualAngleDeg > DegreesPerHalfRevolution) { + actualAngleDeg = actualAngleDeg - DegreesPerRevolution; + } + + double targetAngleDeg = targetAngleIn; + if (targetAngleDeg < DegreesPerRevolution && + targetAngleDeg > DegreesPerHalfRevolution) { + targetAngleDeg = targetAngleDeg - DegreesPerRevolution; + } + + double actualError = fabs(targetAngleDeg - actualAngleDeg); + if (actualError <= allowableError) { + return true; + } + + return false; +} + + bool DrawUtil::isFirstVert(TopoDS_Edge e, TopoDS_Vertex v, double tolerance) { TopoDS_Vertex first = TopExp::FirstVertex(e); diff --git a/src/Mod/TechDraw/App/DrawUtil.h b/src/Mod/TechDraw/App/DrawUtil.h index b3c516428f..c2cb7e3a10 100644 --- a/src/Mod/TechDraw/App/DrawUtil.h +++ b/src/Mod/TechDraw/App/DrawUtil.h @@ -275,6 +275,9 @@ public: static Base::Vector3d toAppSpace(const DrawViewPart& dvp, const Base::Vector3d& inPoint); static Base::Vector3d toAppSpace(const DrawViewPart& dvp, const QPointF& inPoint); + static bool isWithinRange(double actualAngleIn, double targetAngleIn, double allowableError); + + //debugging routines static void dumpVertexes(const char* text, const TopoDS_Shape& s); static void dumpEdge(const char* label, int i, TopoDS_Edge e); diff --git a/src/Mod/TechDraw/App/DrawView.cpp b/src/Mod/TechDraw/App/DrawView.cpp index 897785af6f..f4257726c6 100644 --- a/src/Mod/TechDraw/App/DrawView.cpp +++ b/src/Mod/TechDraw/App/DrawView.cpp @@ -42,9 +42,10 @@ #include "DrawUtil.h" #include "DrawViewClip.h" #include "DrawViewCollection.h" +#include "DrawProjGroup.h" +#include "DrawProjGroupItem.h" #include "Preferences.h" - using namespace TechDraw; using DU = DrawUtil; @@ -652,6 +653,22 @@ void DrawView::setScaleAttribute() } } +//! due to changes made for the "intelligent" view creation tool, testing for a view being an +//! instance of DrawProjGroupItem is no longer reliable, as views not in a group are sometimes +//! created as DrawProjGroupItem without belonging to a group. We now need to test for the existance +//! of the parent DrawProjGroup +bool DrawView::isProjGroupItem(DrawViewPart* item) +{ + auto dpgi = dynamic_cast(item); + if (!dpgi) { + return false; + } + auto group = dpgi->getPGroup(); + if (!group) { + return false; + } + return true; +} int DrawView::prefScaleType() { return Preferences::getPreferenceGroup("General")->GetInt("DefaultScaleType", 0); diff --git a/src/Mod/TechDraw/App/DrawView.h b/src/Mod/TechDraw/App/DrawView.h index 972a5835f3..49f3262d45 100644 --- a/src/Mod/TechDraw/App/DrawView.h +++ b/src/Mod/TechDraw/App/DrawView.h @@ -40,7 +40,7 @@ class DrawPage; class DrawViewCollection; class DrawViewClip; class DrawLeaderLine; -/*class CosmeticVertex;*/ +class DrawViewPart; /** Base class of all View Features in the drawing module */ @@ -123,6 +123,8 @@ public: virtual App::PropertyLink *getOwnerProperty() { return nullptr; } + static bool isProjGroupItem(DrawViewPart* item); + protected: void onBeforeChange(const App::Property *prop) override; void onChanged(const App::Property* prop) override; diff --git a/src/Mod/TechDraw/App/DrawViewSection.cpp b/src/Mod/TechDraw/App/DrawViewSection.cpp index f90aa57582..bbfbb33d06 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.cpp +++ b/src/Mod/TechDraw/App/DrawViewSection.cpp @@ -80,6 +80,7 @@ #include #include #include +#include #include @@ -1152,21 +1153,15 @@ gp_Ax2 DrawViewSection::getSectionCS() const return sectionCS; } -gp_Ax2 DrawViewSection::getProjectionCS(const Base::Vector3d pt) const + +//! return the center of the shape resulting from the cut operation +Base::Vector3d DrawViewSection::getCutCentroid() const { - Base::Vector3d vNormal = SectionNormal.getValue(); - gp_Dir gNormal(vNormal.x, vNormal.y, vNormal.z); - Base::Vector3d vXDir = getXDirection(); - gp_Dir gXDir(vXDir.x, vXDir.y, vXDir.z); - if (DrawUtil::fpCompare(fabs(gNormal.Dot(gXDir)), 1.0)) { - // can not build a gp_Ax2 from these values - throw Base::RuntimeError( - "DVS::getProjectionCS - SectionNormal and XDirection are parallel"); - } - gp_Pnt gOrigin(pt.x, pt.y, pt.z); - return {gOrigin, gNormal, gXDir}; + gp_Pnt inputCenter = ShapeUtils::findCentroid(m_cutPieces, getProjectionCS()); + return Base::Vector3d(inputCenter.X(), inputCenter.Y(), inputCenter.Z()); } + std::vector DrawViewSection::getDrawableLines(int i) { // Base::Console().Message("DVS::getDrawableLines(%d) - lineSets: %d\n", i, m_lineSets.size()); diff --git a/src/Mod/TechDraw/App/DrawViewSection.h b/src/Mod/TechDraw/App/DrawViewSection.h index eddad34073..dbc1b320f0 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.h +++ b/src/Mod/TechDraw/App/DrawViewSection.h @@ -134,7 +134,6 @@ public: virtual TopoDS_Shape getShapeToPrepare() const { return m_cutPieces; } //CS related methods - gp_Ax2 getProjectionCS(Base::Vector3d pt = Base::Vector3d(0.0, 0.0, 0.0)) const override; void setCSFromBase(const std::string sectionName); void setCSFromBase(Base::Vector3d localUnit); void setCSFromLocalUnit(const Base::Vector3d localUnit); @@ -172,6 +171,8 @@ public: TopoDS_Shape makeFaceFromWires(std::vector &inWires); + Base::Vector3d getCutCentroid() const; + public Q_SLOTS: virtual void onSectionCutFinished(void); diff --git a/src/Mod/TechDraw/App/Preferences.cpp b/src/Mod/TechDraw/App/Preferences.cpp index e29dbe708c..99e31ed1f5 100644 --- a/src/Mod/TechDraw/App/Preferences.cpp +++ b/src/Mod/TechDraw/App/Preferences.cpp @@ -599,3 +599,16 @@ bool Preferences::alwaysShowLabel() { return getPreferenceGroup("General")->GetBool("AlwaysShowLabel", false); } + +bool Preferences::SnapViews() +{ + return getPreferenceGroup("General")->GetBool("SnapViews", true); +} + +//! percentage of view size to use in deciding to snap view or not +double Preferences::SnapLimitFactor() +{ + return getPreferenceGroup("General")->GetFloat("SnapLimitFactor", 0.05); +} + + diff --git a/src/Mod/TechDraw/App/Preferences.h b/src/Mod/TechDraw/App/Preferences.h index d55b3e8b84..b4c46e945f 100644 --- a/src/Mod/TechDraw/App/Preferences.h +++ b/src/Mod/TechDraw/App/Preferences.h @@ -138,6 +138,9 @@ public: static bool useCameraDirection(); static bool alwaysShowLabel(); + + static bool SnapViews(); + static double SnapLimitFactor(); }; diff --git a/src/Mod/TechDraw/Gui/DlgPrefsTechDrawGeneral.ui b/src/Mod/TechDraw/Gui/DlgPrefsTechDrawGeneral.ui index 902269a136..b92ccfd245 100644 --- a/src/Mod/TechDraw/Gui/DlgPrefsTechDrawGeneral.ui +++ b/src/Mod/TechDraw/Gui/DlgPrefsTechDrawGeneral.ui @@ -6,8 +6,8 @@ 0 0 - 547 - 915 + 578 + 1073 @@ -886,8 +886,103 @@ for ProjectionGroups + + + + + 0 + 0 + + + + Snapping + + + + + + + + Check this box if you want views to snap into alignment when being dragged. + + + Snap View Alignment + + + true + + + SnapViews + + + /Mod/TechDraw/General + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + View Snapping Factor + + + + + + + When dragging a view, if it is within this fraction of view size of the correct alignment, it will snap into alignment. + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 0.050000000000000 + + + SnapLimitFactor + + + /Mod/TechDraw/General + + + + + + + + + + + 0 + 0 + + + + + 0 + 64 + + + + + 0 + 64 + + 10 @@ -935,6 +1030,11 @@ for ProjectionGroups QLineEdit
Gui/PrefWidgets.h
+ + Gui::PrefDoubleSpinBox + QDoubleSpinBox +
Gui/PrefWidgets.h
+
Gui::PrefFontBox QFontComboBox diff --git a/src/Mod/TechDraw/Gui/DlgPrefsTechDrawGeneralImp.cpp b/src/Mod/TechDraw/Gui/DlgPrefsTechDrawGeneralImp.cpp index 1363e0c9db..30f04ee679 100644 --- a/src/Mod/TechDraw/Gui/DlgPrefsTechDrawGeneralImp.cpp +++ b/src/Mod/TechDraw/Gui/DlgPrefsTechDrawGeneralImp.cpp @@ -79,6 +79,8 @@ void DlgPrefsTechDrawGeneralImp::saveSettings() ui->cb_useCameraDirection->onSave(); ui->cb_alwaysShowLabel->onSave(); + ui->cb_SnapViews->onSave(); + ui->psb_SnapFactor->onSave(); } void DlgPrefsTechDrawGeneralImp::loadSettings() @@ -124,6 +126,9 @@ void DlgPrefsTechDrawGeneralImp::loadSettings() ui->cb_useCameraDirection->onRestore(); ui->cb_alwaysShowLabel->onRestore(); + + ui->cb_SnapViews->onRestore(); + ui->psb_SnapFactor->onRestore(); } /** diff --git a/src/Mod/TechDraw/Gui/QGIView.cpp b/src/Mod/TechDraw/Gui/QGIView.cpp index f9914528ec..0f311d4ead 100644 --- a/src/Mod/TechDraw/Gui/QGIView.cpp +++ b/src/Mod/TechDraw/Gui/QGIView.cpp @@ -1,4 +1,4 @@ -/*************************************************************************** +/*************************************************************************** * Copyright (c) 2012-2013 Luke Parry * * * * This file is part of the FreeCAD CAx development system. * @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -68,15 +69,16 @@ using namespace TechDrawGui; using namespace TechDraw; +using DU = DrawUtil; const float labelCaptionFudge = 0.2f; // temp fiddle for devel QGIView::QGIView() :QGraphicsItemGroup(), - viewObj(nullptr), - m_innerView(false), - m_multiselectActivated(false), - snapping(false) + viewObj(nullptr), + m_innerView(false), + m_multiselectActivated(false), + snapping(false) { setCacheMode(QGraphicsItem::NoCache); setHandlesChildEvents(false); @@ -158,7 +160,7 @@ void QGIView::alignTo(QGraphicsItem*item, const QString &alignment) QVariant QGIView::itemChange(GraphicsItemChange change, const QVariant &value) { -// Base::Console().Message("QGIV::itemChange(%d)\n", change); + // Base::Console().Message("QGIV::itemChange(%d)\n", change); if(change == ItemPositionChange && scene()) { QPointF newPos = value.toPointF(); //position within parent! @@ -184,7 +186,7 @@ QVariant QGIView::itemChange(GraphicsItemChange change, const QVariant &value) } } - // tell the feature that we have moved + // 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 @@ -207,89 +209,196 @@ QVariant QGIView::itemChange(GraphicsItemChange change, const QVariant &value) return QGraphicsItemGroup::itemChange(change, value); } -void QGIView::snapPosition(QPointF& mPos) +//! align this view with others. newPosition is in this view's parent's coord +//! system. if this view is not in a ProjectionGroup, then this is the scene +//! position, otherwise it is the position within the ProjectionGroup. +void QGIView::snapPosition(QPointF& newPosition) { - // For general views we check if the view is close to aligned vertically or horizontally to another view. + if (!Preferences::SnapViews()) { + return; + } - // First get a list of the views of the page. - auto* mdi = dynamic_cast(Gui::getMainWindow()->activeWindow()); - if (!mdi) { + auto feature = getViewObject(); + if (!feature) { return; } - ViewProviderPage* vp = mdi->getViewProviderPage(); - if (!vp) { + + auto dvp = dynamic_cast(feature); + if (dvp && + !dvp->hasGeometry()) { + // too early. wait for updates to finish. return; } - QGSPage* scenePage = vp->getQGSPage(); + + auto vpPage = getViewProviderPage(feature); + + QGSPage* scenePage = vpPage->getQGSPage(); if (!scenePage) { return; } - std::vector views = scenePage->getViews(); - qreal snapPercent = 0.05; - - auto* sectionView = dynamic_cast(getViewObject()); + auto* sectionView = dynamic_cast(feature); 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; - } + snapSectionView(sectionView, newPosition); + return; } - for (auto* view : views) { - if (view == this) { continue; } + // For general views we check if the view is close to aligned vertically or horizontally to another view. - QPointF vPos = view->pos(); - qreal dx = view->boundingRect().width() * snapPercent; - qreal dy = view->boundingRect().height() * snapPercent; - if (fabs(mPos.x() - vPos.x()) < dx) { - mPos.setX(vPos.x()); - break; + // if we are not a section view, then we could be in a projection group and + // need to get the correct scene position. + auto newScenePos = newPosition; + if (parentItem()) { + newScenePos = parentItem()->mapToScene(newPosition); + } + + // First get a list of the views of the page. + qreal snapPercent = Preferences::SnapLimitFactor(); + std::vector views = scenePage->getViews(); + for (auto* view : views) { + if (view == this) { + continue; } - else if (fabs(mPos.y() - vPos.y()) < dy) { - mPos.setY(vPos.y()); - break; + auto viewFeature = view->getViewObject(); + auto viewDvp = dynamic_cast(viewFeature); + + auto viewScenePos = view->scenePos(); + if (viewDvp && + DrawView::isProjGroupItem(viewDvp)) { + viewScenePos = DU::toQPointF(projItemPagePos(viewDvp)); + viewScenePos = DU::invertY(Rez::guiX(viewScenePos)); + } + + auto xwindow = view->boundingRect().width() * snapPercent; + auto ywindow = view->boundingRect().height() * snapPercent; + + auto xerror = fabs(newScenePos.x() - viewScenePos.x()); + auto yerror = fabs(newScenePos.y() - viewScenePos.y()); + + // if the smaller of vertical and horizontal errors is within the acceptable + // window, snap to position. + if (xerror <= yerror && + xerror <= xwindow) { + newScenePos.setX(viewScenePos.x()); + if (parentItem()) { + newScenePos = parentItem()->mapFromScene(newScenePos); + } + newPosition = newScenePos; + return; + } + + if (yerror < xerror && + yerror <= ywindow) { + newScenePos.setY(viewScenePos.y()); + if (parentItem()) { + newScenePos = parentItem()->mapFromScene(newScenePos); + } + newPosition = newScenePos; + return; } } } + +//! snap this section view to its base view. The section should be positioned on +//! line from the base view along the section normal direction, ie the same direction +//! as the arrows on the section line. +// Note: positions are in Qt inverted Y coordinates. They need to be converted before +// doing math on them, then converted back on return. +// Note: section views are never inside a ProjectionGroup, so their position is +// always in scene coordinates. +void QGIView::snapSectionView(const TechDraw::DrawViewSection* sectionView, + QPointF& newPosition) +{ + auto* baseView = sectionView->getBaseDVP(); + if (!baseView) { + return; + } + auto* vpdv = dynamic_cast(getViewProvider(baseView)); + if (!vpdv) { + return; + } + auto* qgiv(dynamic_cast(vpdv->getQView())); + if (!qgiv) { + return; + } + + Base::Vector3d arrowDirection = sectionView->SectionNormal.getValue() * -1; + auto arrowDirectionOnBase = baseView->projectPoint(arrowDirection, false); + if (arrowDirectionOnBase.Length() < Precision::Confusion()) { + return; + } + arrowDirectionOnBase.Normalize(); + double baseSize = Rez::guiX(baseView->getSizeAlongVector(arrowDirectionOnBase)); + double snapDist = baseSize * getScale() * Preferences::SnapLimitFactor(); + + // find the scene position of the SO on the base view + auto baseX = baseView->X.getValue(); + auto baseY = baseView->Y.getValue(); + Base::Vector3d baseScenePos{baseX, baseY, 0}; // paper space position + if (DrawView::isProjGroupItem(baseView)) { + baseScenePos = projItemPagePos(baseView); + } + auto sectionOrg3d = sectionView->SectionOrigin.getValue(); + auto shapeCenter3d = baseView->getCurrentCentroid(); + auto baseShapeCenter = baseView->projectPoint(shapeCenter3d, false); + auto baseSectionOrg = baseView->projectPoint(sectionOrg3d, false); + auto baseSOOffset = (baseSectionOrg - baseShapeCenter) * baseView->getScale(); + auto baseSOScenePos = baseScenePos + baseSOOffset; + + // find the SO offset from origin on the rotated & scaled sectionView + auto sectionCutCenter = sectionView->projectPoint(sectionView->getCutCentroid(), false); + auto sectionSectionOrg = sectionView->projectPoint(sectionOrg3d, false); + auto sectionSOOffset = (sectionSectionOrg - sectionCutCenter) * sectionView->getScale(); + auto sectionRotationDeg = sectionView->Rotation.getValue(); + sectionSOOffset.RotateZ(Base::toRadians(sectionRotationDeg)); + + // from here on, we work with scene units (1/10 mm) + sectionSOOffset = Rez::guiX(sectionSOOffset); + baseSOScenePos = Rez::guiX(baseSOScenePos); + + // check our alignment + auto newSOPosition = DU::invertY(DU::toVector3d(newPosition)) + sectionSOOffset; + + Base::Vector3d actualAlignmentVector = newSOPosition - baseSOScenePos; + actualAlignmentVector.Normalize(); + + // if we are not on the correct side of the section line, we should not try to snap + auto dot = arrowDirectionOnBase.Dot(actualAlignmentVector); + if (dot <= 0) { + return; + } + + auto pointOnArrowLine = newSOPosition.Perpendicular(baseSOScenePos, arrowDirectionOnBase); + auto errorVector = pointOnArrowLine - newSOPosition; + if (errorVector.Length() < snapDist) { + // get the position point corresponding to our SO alignment + auto netPosition = pointOnArrowLine - sectionSOOffset; + netPosition = DU::invertY(netPosition); + newPosition = DU::toQPointF(netPosition); + } + + return; +} + +Base::Vector3d QGIView::projItemPagePos(DrawViewPart* item) +{ + if (!DrawView::isProjGroupItem(item)) { + return Base::Vector3d(0, 0, 0); + } + auto dpgi = static_cast(item); + auto group = dpgi->getPGroup(); + + auto itemX = dpgi->X.getValue(); + auto itemY = dpgi->Y.getValue(); + Base::Vector3d itemOffsetPos{itemX, itemY, 0}; // relative to group + auto groupX = group->X.getValue(); + auto groupY = group->Y.getValue(); + Base::Vector3d groupPagePos{groupX, groupY, 0}; // relative to page + return groupPagePos + itemOffsetPos; +} + + void QGIView::mousePressEvent(QGraphicsSceneMouseEvent * event) { Qt::KeyboardModifiers originalModifiers = event->modifiers(); @@ -334,7 +443,7 @@ void QGIView::mouseReleaseEvent(QGraphicsSceneMouseEvent * event) void QGIView::hoverEnterEvent(QGraphicsSceneHoverEvent *event) { -// Base::Console().Message("QGIV::hoverEnterEvent()\n"); + // Base::Console().Message("QGIV::hoverEnterEvent()\n"); Q_UNUSED(event); // TODO don't like this but only solution at the minute (MLP) if (isSelected()) { @@ -360,7 +469,7 @@ void QGIView::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) //sets position in /Gui(graphics), not /App void QGIView::setPosition(qreal xPos, qreal yPos) { -// Base::Console().Message("QGIV::setPosition(%.3f, %.3f) (gui)\n", x, y); + // Base::Console().Message("QGIV::setPosition(%.3f, %.3f) (gui)\n", x, y); double newX = xPos; double newY = -yPos; double oldX = pos().x(); @@ -389,9 +498,9 @@ QGIViewClip* QGIView::getClipGroup() void QGIView::updateView(bool forceUpdate) { -// Base::Console().Message("QGIV::updateView() - %s\n", getViewObject()->getNameInDocument()); + // Base::Console().Message("QGIV::updateView() - %s\n", getViewObject()->getNameInDocument()); - //allow/prevent dragging + //allow/prevent dragging if (getViewObject()->isLocked()) { setFlag(QGraphicsItem::ItemIsMovable, false); } else { @@ -415,10 +524,10 @@ void QGIView::updateView(bool forceUpdate) //QGIVP derived classes do not need a rotate view method as rotation is handled on App side. void QGIView::rotateView() { -//NOTE: QPainterPaths have to be rotated individually. This transform handles Rotation for everything else. -//Scale is handled in GeometryObject for DVP & descendents -//Objects not descended from DVP must setScale for themselves -//note that setTransform(, ,rotation, ,) is not the same as setRotation!!! + //NOTE: QPainterPaths have to be rotated individually. This transform handles Rotation for everything else. + //Scale is handled in GeometryObject for DVP & descendents + //Objects not descended from DVP must setScale for themselves + //note that setTransform(, ,rotation, ,) is not the same as setRotation!!! double rot = getViewObject()->Rotation.getValue(); QPointF centre = boundingRect().center(); setTransform(QTransform().translate(centre.x(), centre.y()).rotate(-rot).translate(-centre.x(), -centre.y())); @@ -455,7 +564,7 @@ void QGIView::setViewFeature(TechDraw::DrawView *obj) viewObj = obj; viewName = obj->getNameInDocument(); - //mark the actual QGraphicsItem so we can check what's in the scene later + //mark the actual QGraphicsItem so we can check what's in the scene later setData(0, QString::fromUtf8("QGIV")); setData(1, QString::fromUtf8(obj->getNameInDocument())); } @@ -470,7 +579,7 @@ void QGIView::toggleCache(bool state) void QGIView::draw() { -// Base::Console().Message("QGIV::draw()\n"); + // Base::Console().Message("QGIV::draw()\n"); double xFeat, yFeat; if (getViewObject()) { xFeat = Rez::guiX(getViewObject()->X.getValue()); @@ -489,7 +598,7 @@ void QGIView::draw() void QGIView::drawCaption() { -// Base::Console().Message("QGIV::drawCaption()\n"); + // Base::Console().Message("QGIV::drawCaption()\n"); prepareGeometryChange(); QRectF displayArea = customChildrenBoundingRect(); m_caption->setDefaultTextColor(m_colCurrent); @@ -515,7 +624,7 @@ void QGIView::drawCaption() void QGIView::drawBorder() { -// Base::Console().Message("QGIV::drawBorder() - %s\n", getViewName()); + // Base::Console().Message("QGIV::drawBorder() - %s\n", getViewName()); auto feat = getViewObject(); if (!feat) return; @@ -524,9 +633,9 @@ void QGIView::drawBorder() auto vp = static_cast(getViewProvider(getViewObject())); if (!getFrameState() && !vp->KeepLabel.getValue()) { - m_label->hide(); - m_border->hide(); - m_lock->hide(); + m_label->hide(); + m_border->hide(); + m_lock->hide(); return; } @@ -596,8 +705,8 @@ void QGIView::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q QStyleOptionGraphicsItem myOption(*option); myOption.state &= ~QStyle::State_Selected; -// painter->setPen(Qt::red); -// painter->drawRect(boundingRect()); //good for debugging + // painter->setPen(Qt::red); + // painter->drawRect(boundingRect()); //good for debugging QGraphicsItemGroup::paint(painter, &myOption, widget); } @@ -622,15 +731,15 @@ QRectF QGIView::customChildrenBoundingRect() const continue; } if ( (child->type() != dimItemType) && - (child->type() != leaderItemType) && - (child->type() != textLeaderItemType) && - (child->type() != editablePathItemType) && - (child->type() != movableTextItemType) && - (child->type() != borderItemType) && - (child->type() != labelItemType) && - (child->type() != weldingSymbolItemType) && - (child->type() != captionItemType) && - (child->type() != centerMarkItemType)) { + (child->type() != leaderItemType) && + (child->type() != textLeaderItemType) && + (child->type() != editablePathItemType) && + (child->type() != movableTextItemType) && + (child->type() != borderItemType) && + (child->type() != labelItemType) && + (child->type() != weldingSymbolItemType) && + (child->type() != captionItemType) && + (child->type() != centerMarkItemType)) { QRectF childRect = mapFromItem(child, child->boundingRect()).boundingRect(); result = result.united(childRect); } @@ -710,7 +819,7 @@ void QGIView::removeChild(QGIView* child) bool QGIView::getFrameState() { -// Base::Console().Message("QGIV::getFrameState() - %s\n", getViewName()); + // Base::Console().Message("QGIV::getFrameState() - %s\n", getViewName()); TechDraw::DrawView* dv = getViewObject(); if (!dv) return true; @@ -734,7 +843,7 @@ void QGIView::hideFrame() void QGIView::addArbitraryItem(QGraphicsItem* qgi) { if (qgi) { -// m_randomItems.push_back(qgi); + // m_randomItems.push_back(qgi); addToGroup(qgi); qgi->show(); } @@ -772,7 +881,7 @@ void QGIView::setStackFromVP() { TechDraw::DrawView* feature = getViewObject(); ViewProviderDrawingView* vpdv = static_cast - (getViewProvider(feature)); + (getViewProvider(feature)); int z = vpdv->getZ(); setStack(z); } @@ -795,7 +904,7 @@ QColor QGIView::getSelectColor() Base::Reference QGIView::getParmGroupCol() { return App::GetApplication().GetUserParameter() - .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Colors"); + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Colors"); } //convert input font size in mm to scene units diff --git a/src/Mod/TechDraw/Gui/QGIView.h b/src/Mod/TechDraw/Gui/QGIView.h index b1ce7c0f04..7580b0fd5a 100644 --- a/src/Mod/TechDraw/Gui/QGIView.h +++ b/src/Mod/TechDraw/Gui/QGIView.h @@ -55,6 +55,8 @@ class ViewProvider; namespace TechDraw { class DrawView; +class DrawViewSection; +class DrawViewPart; } namespace TechDrawGui @@ -124,7 +126,9 @@ public: bool isSnapping() { return snapping; } void snapPosition(QPointF& position); - + void snapSectionView(const TechDraw::DrawViewSection* sectionView, + QPointF& newPosition); + Base::Vector3d projItemPagePos(TechDraw::DrawViewPart* item); void alignTo(QGraphicsItem*, const QString &alignment); QColor prefNormalColor(); //preference @@ -202,6 +206,8 @@ private: double m_lockHeight; int m_zOrder; + bool m_snapped{false}; + }; } // namespace