From f523f6c3ad4e8db70f81b67486c8311dfcf8b2eb Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Fri, 26 Apr 2024 21:27:32 +0200 Subject: [PATCH] TechDraw: Introduce dimension snapping --- src/Mod/TechDraw/Gui/QGIViewDimension.cpp | 88 ++++++++++++++++++++++- 1 file changed, 85 insertions(+), 3 deletions(-) diff --git a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp index c8a967b38e..00b2fa8520 100644 --- a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp @@ -53,6 +53,7 @@ #include "QGIDimLines.h" #include "QGIVertex.h" #include "QGCustomSvg.h" +#include "TaskSelectLineAttributes.h" #include "ViewProviderDimension.h" #include "ZVALUE.h" @@ -155,12 +156,24 @@ void QGIDatumLabel::snapPosition(QPointF& pos) return; } - // First we try to snap the label to its center position. + // We only have snap for distances constraints + std::string type = dim->Type.getValueAsString(); + if(type != "Distance" && type != "DistanceX" && type != "DistanceY") { + return; + } + + // 1 - We try to snap the label to its center position. pointPair pp = dim->getLinearPoints(); Base::Vector3d p1_3d = Rez::guiX(pp.first()); Base::Vector3d p2_3d = Rez::guiX(pp.second()); Base::Vector2d p1 = Base::Vector2d(p1_3d.x, p1_3d.y); Base::Vector2d p2 = Base::Vector2d(p2_3d.x, p2_3d.y); + if (type == "DistanceX") { + p2 = Base::Vector2d(p2.x, p1.y); + } + else if (type == "DistanceY") { + p2 = Base::Vector2d(p1.x, p2.y); + } Base::Vector2d mid = (p1 + p2) * 0.5; Base::Vector2d dir = p2 - p1; Base::Vector2d normal = Base::Vector2d(-dir.y, dir.x); @@ -171,11 +184,80 @@ void QGIDatumLabel::snapPosition(QPointF& pos) projPnt = projPnt + mid; if ((projPnt - posV).Length() < dir.Length() * snapPercent) { - pos.setX(projPnt.x - m_dimText->boundingRect().width() * 0.5); - pos.setY(projPnt.y - m_dimText->boundingRect().height() * 0.5); + posV = projPnt; + pos.setX(posV.x - m_dimText->boundingRect().width() * 0.5); + pos.setY(posV.y - m_dimText->boundingRect().height() * 0.5); } + // 2 - We check for coord/chain dimensions to offer proper snapping + auto* qgiv = dynamic_cast(qgivd->parentItem()); + if (qgiv) { + auto* dvp = dynamic_cast(qgiv->getViewObject()); + if (dvp) { + std::vector dims = dvp->getDimensions(); + double dimSpacing = Rez::guiX(activeDimAttributes.getCascadeSpacing()); + snapPercent = 0.2; + for (auto& d : dims) { + if (d == dim) { continue; } + + std::string dType = d->Type.getValueAsString(); + if (dType != type) { + continue; + } + + pp = d->getLinearPoints(); + Base::Vector3d ip1_3d = Rez::guiX(pp.first()); + Base::Vector3d ip2_3d = Rez::guiX(pp.second()); + + Base::Vector2d ip1 = Base::Vector2d(ip1_3d.x, ip1_3d.y); + Base::Vector2d ip2 = Base::Vector2d(ip2_3d.x, ip2_3d.y); + if (type == "DistanceX") { + ip2 = Base::Vector2d(ip2.x, ip1.y); + } + else if (type == "DistanceY") { + ip2 = Base::Vector2d(ip1.x, ip2.y); + } + Base::Vector2d imid = (ip1 + ip2) * 0.5; + Base::Vector2d idir = ip2 - ip1; + Base::Vector2d inormal = Base::Vector2d(-idir.y, idir.x); + + if (type == "Distance" && fabs(dir.x * idir.y - dir.y * idir.x) > Precision::Confusion()) { + //dimensions not parallel + continue; + } + + auto* vp = dynamic_cast(Gui::Application::Instance->getViewProvider(d)); + if (!vp) { continue; } + auto* qgivDi(dynamic_cast(vp->getQView())); + if (!qgivDi) { continue; } + auto labeli = qgivDi->getDatumLabel(); + if (!labeli) { continue; } + QPointF posi = labeli->pos(); + Base::Vector2d posVi = Base::Vector2d(posi.x() + labeli->m_dimText->boundingRect().width() * 0.5, + posi.y() + labeli->m_dimText->boundingRect().height() * 0.5); + + Base::Vector2d projPnt2; + projPnt2.ProjectToLine(posV - posVi, idir); + projPnt2 = projPnt2 + posVi; + + if ((projPnt2 - posV).Length() < dimSpacing * snapPercent) { + posV = projPnt2; + pos.setX(posV.x - m_dimText->boundingRect().width() * 0.5); + pos.setY(posV.y - m_dimText->boundingRect().height() * 0.5); + break; + } + else if (fabs((projPnt2 - posV).Length() - fabs(dimSpacing)) < dimSpacing * snapPercent) { + posV = projPnt2 + (posV - projPnt2).Normalize() * dimSpacing; + pos.setX(posV.x - m_dimText->boundingRect().width() * 0.5); + pos.setY(posV.y - m_dimText->boundingRect().height() * 0.5); + break; + } + } + } + } + + setPos(pos); // no infinite loop because if pos doesn't change then itemChanged is not triggered. }