From 29c5528fde93fd73c64998b593ed635cf4f4dda4 Mon Sep 17 00:00:00 2001 From: wandererfan Date: Wed, 6 May 2020 19:19:05 -0400 Subject: [PATCH] [TD]oblique section lines --- src/Mod/TechDraw/App/DrawUtil.cpp | 56 ++++++++ src/Mod/TechDraw/App/DrawUtil.h | 4 + src/Mod/TechDraw/App/DrawViewSection.cpp | 32 +++++ src/Mod/TechDraw/App/DrawViewSection.h | 2 + src/Mod/TechDraw/Gui/QGISectionLine.cpp | 160 +++++++++++++++-------- src/Mod/TechDraw/Gui/QGISectionLine.h | 10 ++ src/Mod/TechDraw/Gui/QGIViewPart.cpp | 97 +++----------- 7 files changed, 228 insertions(+), 133 deletions(-) diff --git a/src/Mod/TechDraw/App/DrawUtil.cpp b/src/Mod/TechDraw/App/DrawUtil.cpp index 8790bc9283..d753a19e12 100644 --- a/src/Mod/TechDraw/App/DrawUtil.cpp +++ b/src/Mod/TechDraw/App/DrawUtil.cpp @@ -284,6 +284,62 @@ bool DrawUtil::fpCompare(const double& d1, const double& d2, double tolerance) return result; } +//brute force intersection points of line(point, dir) with box(xRange, yRange) +std::pair DrawUtil::boxIntersect2d(Base::Vector3d point, + Base::Vector3d dirIn, + double xRange, + double yRange) +{ + std::pair result; + Base::Vector3d p1, p2; + Base::Vector3d dir = dirIn; + dir.Normalize(); + // y = mx + b + // m = (y1 - y0) / (x1 - x0) + if (DrawUtil::fpCompare(dir.x, 0.0) ) { + p1 = Base::Vector3d(0.0, - yRange / 2.0, 0.0); + p2 = Base::Vector3d(0.0, yRange / 2.0, 0.0); + } else { + double slope = dir.y / dir.x; + double left = -xRange / 2.0; + double right = xRange / 2.0; + double top = yRange / 2.0; + double bottom = -yRange / 2.0; + double yLeft = point.y - slope * (point.x - left) ; + double yRight = point.y - slope * (point.x - right); + double xTop = point.x - ( (point.y - top) / slope ); + double xBottom = point.x - ( (point.y - bottom) / slope ); + + if ( (bottom < yLeft) && + (top > yLeft) ) { + p1 = Base::Vector3d(left, yLeft); + } else if (yLeft <= bottom) { + p1 = Base::Vector3d(xBottom, bottom); + } else if (yLeft >= top) { + p1 = Base::Vector3d(xTop, top); + } + + if ( (bottom < yRight) && + (top > yRight) ) { + p2 = Base::Vector3d(right, yRight); + } else if (yRight <= bottom) { + p2 = Base::Vector3d(xBottom, bottom); + } else if (yRight >= top) { + p2 = Base::Vector3d(xTop, top); + } + } + result.first = p1; + result.second = p2; + Base::Vector3d dirCheck = p2 - p1; + dirCheck.Normalize(); + if (!dir.IsEqual(dirCheck, 0.00001)) { + result.first = p2; + result.second = p1; + } + + return result; +} + Base::Vector3d DrawUtil::vertex2Vector(const TopoDS_Vertex& v) { gp_Pnt gp = BRep_Tool::Pnt(v); diff --git a/src/Mod/TechDraw/App/DrawUtil.h b/src/Mod/TechDraw/App/DrawUtil.h index aa70753220..13d5f8cfb6 100644 --- a/src/Mod/TechDraw/App/DrawUtil.h +++ b/src/Mod/TechDraw/App/DrawUtil.h @@ -79,6 +79,10 @@ class TechDrawExport DrawUtil { static bool isFirstVert(TopoDS_Edge e, TopoDS_Vertex v, double tolerance = VERTEXTOLERANCE); static bool isLastVert(TopoDS_Edge e, TopoDS_Vertex v, double tolerance = VERTEXTOLERANCE); static bool fpCompare(const double& d1, const double& d2, double tolerance = FLT_EPSILON); + static std::pair boxIntersect2d(Base::Vector3d point, + Base::Vector3d dir, + double xRange, + double yRange) ; static Base::Vector3d vertex2Vector(const TopoDS_Vertex& v); static std::string formatVector(const Base::Vector3d& v); static std::string formatVector(const gp_Dir& v); diff --git a/src/Mod/TechDraw/App/DrawViewSection.cpp b/src/Mod/TechDraw/App/DrawViewSection.cpp index d7364eee6c..368e67fede 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.cpp +++ b/src/Mod/TechDraw/App/DrawViewSection.cpp @@ -677,6 +677,38 @@ TopoDS_Face DrawViewSection::projectFace(const TopoDS_Shape &face, return projectedFace; } + +//calculate the ends of the section line in BaseView's coords +std::pair DrawViewSection::sectionLineEnds(void) +{ + std::pair result; + + auto sNorm = SectionNormal.getValue(); + double angle = M_PI / 2.0; + auto axis = getBaseDVP()->Direction.getValue(); + Base::Vector3d stdOrg(0.0, 0.0, 0.0); + Base::Vector3d sLineDir = DrawUtil::vecRotate(sNorm, angle, axis, stdOrg); + sLineDir.Normalize(); + Base::Vector3d sLineDir2 = - axis.Cross(sNorm); + sLineDir2.Normalize(); + Base::Vector3d sLineOnBase = getBaseDVP()->projectPoint(sLineDir2); + sLineOnBase.Normalize(); + + auto sOrigin = SectionOrigin.getValue(); + Base::Vector3d adjSectionOrg = sOrigin - getBaseDVP()->getOriginalCentroid(); + Base::Vector3d sOrgOnBase = getBaseDVP()->projectPoint(adjSectionOrg); + sOrgOnBase /= getScale(); + + auto bbx = getBaseDVP()->getBoundingBox(); + double xRange = bbx.MaxX - bbx.MinX; + xRange /= getScale(); + double yRange = bbx.MaxY - bbx.MinY; + yRange /= getScale(); + result = DrawUtil::boxIntersect2d(sOrgOnBase, sLineOnBase, xRange, yRange); + + return result; +} + //this should really be in BoundBox.h //!check if point is in box or on boundary of box //!compare to isInBox which doesn't allow on boundary diff --git a/src/Mod/TechDraw/App/DrawViewSection.h b/src/Mod/TechDraw/App/DrawViewSection.h index b6e257998d..154e829b7a 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.h +++ b/src/Mod/TechDraw/App/DrawViewSection.h @@ -119,6 +119,8 @@ public: static const char* SectionDirEnums[]; static const char* CutSurfaceEnums[]; + std::pair sectionLineEnds(void); + protected: TopoDS_Compound sectionFaces; std::vector sectionFaceWires; diff --git a/src/Mod/TechDraw/Gui/QGISectionLine.cpp b/src/Mod/TechDraw/Gui/QGISectionLine.cpp index b8e9ee6c3d..34b41a13b3 100644 --- a/src/Mod/TechDraw/Gui/QGISectionLine.cpp +++ b/src/Mod/TechDraw/Gui/QGISectionLine.cpp @@ -75,6 +75,13 @@ QGISectionLine::QGISectionLine() void QGISectionLine::draw() { prepareGeometryChange(); + int format = getPrefSectionStandard(); + if (format == ANSISTANDARD) { //"ASME"/"ANSI" + extensionEndsTrad(); + } else { + extensionEndsISO(); + } + makeLine(); makeArrows(); makeSymbols(); @@ -84,37 +91,15 @@ void QGISectionLine::draw() void QGISectionLine::makeLine() { QPainterPath pp; - QPointF beginExtLine1,beginExtLine2; //ext line start pts for measure Start side and measure End side - QPointF endExtLine1, endExtLine2; - QPointF offsetDir(m_arrowDir.x,-m_arrowDir.y); - int format = getPrefSectionStandard(); - if (format == ANSISTANDARD) { //"ASME"/"ANSI" - //draw from section line endpoint - QPointF offsetBegin = m_extLen * offsetDir; - beginExtLine1 = m_start; //from - beginExtLine2 = m_end; //to - endExtLine1 = m_start + offsetBegin; - endExtLine2 = m_end + offsetBegin; - pp.moveTo(beginExtLine1); - pp.lineTo(endExtLine1); - pp.moveTo(beginExtLine2); - pp.lineTo(endExtLine2); - } else { //"ISO" - //draw from just short of section line away from section line - QPointF offsetBegin = Rez::guiX(QGIArrow::getOverlapAdjust(0,QGIArrow::getPrefArrowSize())) * offsetDir; - QPointF offsetEnd = offsetBegin + (m_extLen * offsetDir); - beginExtLine1 = m_start - offsetBegin; - beginExtLine2 = m_end - offsetBegin; - endExtLine1 = m_start - offsetEnd; - endExtLine2 = m_end - offsetEnd; - pp.moveTo(beginExtLine1); - pp.lineTo(endExtLine1); - pp.moveTo(beginExtLine2); - pp.lineTo(endExtLine2); - } - pp.moveTo(m_end); - pp.lineTo(m_start); //sectionLine + pp.moveTo(m_beginExt1); + pp.lineTo(m_endExt1); + + pp.moveTo(m_beginExt2); + pp.lineTo(m_endExt2); + + pp.moveTo(m_start); + pp.lineTo(m_end); m_line->setPath(pp); } @@ -165,8 +150,14 @@ void QGISectionLine::makeArrowsTrad() QPointF posArrow1,posArrow2; QPointF offsetDir(m_arrowDir.x,-m_arrowDir.y); //remember Y dir is flipped - double offsetLength = m_extLen + Rez::guiX(QGIArrow::getOverlapAdjust(0,QGIArrow::getPrefArrowSize())); + + double oblique = 1.0; + if ( !DrawUtil::fpCompare((m_arrowDir.x + m_arrowDir.y), 1.0) ) { + oblique = 1.25; + } + double offsetLength = (m_extLen * oblique) + Rez::guiX(QGIArrow::getPrefArrowSize()); QPointF offsetVec = offsetLength * offsetDir; + posArrow1 = m_start + offsetVec; posArrow2 = m_end + offsetVec; @@ -195,58 +186,114 @@ void QGISectionLine::makeSymbols() void QGISectionLine::makeSymbolsTrad() { - QPointF extLineStart,extLineEnd; - QPointF offset(m_arrowDir.x,-m_arrowDir.y); - offset = 1.5 * m_extLen * offset; - extLineStart = m_start + offset; - extLineEnd = m_end + offset; prepareGeometryChange(); m_symFont.setPixelSize(QGIView::calculateFontPixelSize(m_symSize)); m_symbol1->setFont(m_symFont); m_symbol1->setPlainText(QString::fromUtf8(m_symbol)); + m_symbol2->setFont(m_symFont); + m_symbol2->setPlainText(QString::fromUtf8(m_symbol)); QRectF symRect = m_symbol1->boundingRect(); double symWidth = symRect.width(); double symHeight = symRect.height(); - double symbolFudge = 1.0; + double symbolFudge = 0.75; double angle = atan2f(m_arrowDir.y,m_arrowDir.x); if (angle < 0.0) { angle = 2 * M_PI + angle; } Base::Vector3d adjustVector(cos(angle) * symWidth, sin(angle) * symHeight, 0.0); - adjustVector = (DrawUtil::invertY(adjustVector) / 2.0) * symbolFudge; + adjustVector = DrawUtil::invertY(adjustVector) * symbolFudge; QPointF qAdjust(adjustVector.x, adjustVector.y); - extLineStart += qAdjust; - m_symbol1->centerAt(extLineStart); + QPointF posSymbol1 = m_arrow1->pos() + qAdjust; + m_symbol1->centerAt(posSymbol1); - m_symbol2->setFont(m_symFont); - m_symbol2->setPlainText(QString::fromUtf8(m_symbol)); - extLineEnd += qAdjust; - m_symbol2->centerAt(extLineEnd); + QPointF posSymbol2 = m_arrow2->pos() + qAdjust; + m_symbol2->centerAt(posSymbol2); } void QGISectionLine::makeSymbolsISO() { - QPointF symPosStart, symPosEnd; - QPointF dist = (m_start - m_end); - double lenDist = sqrt(dist.x()*dist.x() + dist.y()*dist.y()); - QPointF distDir = dist / lenDist; - - QPointF offset = m_extLen * distDir; - symPosStart = m_start + offset; - symPosEnd = m_end - offset; - prepareGeometryChange(); m_symFont.setPixelSize(QGIView::calculateFontPixelSize(m_symSize)); m_symbol1->setFont(m_symFont); m_symbol1->setPlainText(QString::fromUtf8(m_symbol)); - m_symbol1->centerAt(symPosStart); - m_symbol2->setFont(m_symFont); m_symbol2->setPlainText(QString::fromUtf8(m_symbol)); - m_symbol2->centerAt(symPosEnd); + QPointF symPosStart, symPosEnd; + //no normalize() for QPointF + QPointF dist = (m_start - m_end); + double lenDist = sqrt(dist.x()*dist.x() + dist.y()*dist.y()); + QPointF offsetDir = dist / lenDist; + + QRectF symRect = m_symbol1->boundingRect(); + double symWidth = symRect.width(); + double symHeight = symRect.height(); + + double symbolFudge = 0.75; + double angle = atan2f(offsetDir.y(), offsetDir.x()); + if (angle < 0.0) { + angle = 2.0 * M_PI + angle; + } + Base::Vector3d adjustVector(cos(angle) * symWidth, sin(angle) * symHeight, 0.0); + adjustVector = adjustVector * symbolFudge; + QPointF qAdjust(adjustVector.x, adjustVector.y); + + symPosStart = m_start + qAdjust; + symPosEnd = m_end - qAdjust; + + m_symbol1->centerAt(symPosStart); + m_symbol2->centerAt(symPosEnd); +} + +void QGISectionLine::extensionEndsTrad() +{ + QPointF offsetDir(m_arrowDir.x,-m_arrowDir.y); + + //extensions for oblique section line needs to be a bit longer + double oblique = 1.0; + if ( !DrawUtil::fpCompare((m_arrowDir.x + m_arrowDir.y), 1.0) ) { + oblique = 1.25; + } + + //draw from section line endpoint + QPointF offsetEnd = oblique * m_extLen * offsetDir; + m_beginExt1 = m_start; + m_endExt1 = m_start + offsetEnd; + m_beginExt2 = m_end; + m_endExt2 = m_end + offsetEnd; +} + +void QGISectionLine::extensionEndsISO() +{ + //lines are offset to other side of section line! + QPointF offsetDir(m_arrowDir.x,-m_arrowDir.y); + offsetDir = offsetDir * -1.0; + + //extensions for oblique section line needs to be a bit longer? + //this is just esthetics + double oblique = 1.0; + if ( !DrawUtil::fpCompare((m_arrowDir.x + m_arrowDir.y), 1.0) ) { + oblique = 1.10; + } + + //draw from section line endpoint less arrow length + QPointF offsetStart = offsetDir * Rez::guiX(QGIArrow::getPrefArrowSize()); + QPointF offsetEnd = oblique * m_extLen * offsetDir; + + m_beginExt1 = m_start + offsetStart; + m_endExt1 = m_start + offsetStart + offsetEnd; + m_beginExt2 = m_end + offsetStart; + m_endExt2 = m_end + offsetStart + offsetEnd; +} + +void QGISectionLine::setEnds(Base::Vector3d l1, Base::Vector3d l2) +{ + m_l1 = l1; + m_start = QPointF(l1.x, l1.y); + m_l2 = l2; + m_end = QPointF(l2.x, l2.y); } void QGISectionLine::setBounds(double x1,double y1,double x2,double y2) @@ -269,6 +316,7 @@ void QGISectionLine::setDirection(double xDir,double yDir) void QGISectionLine::setDirection(Base::Vector3d dir) { m_arrowDir = dir; + m_arrowDir.Normalize(); } void QGISectionLine::setFont(QFont f, double fsize) diff --git a/src/Mod/TechDraw/Gui/QGISectionLine.h b/src/Mod/TechDraw/Gui/QGISectionLine.h index 608e7e2030..39b1d4abd6 100644 --- a/src/Mod/TechDraw/Gui/QGISectionLine.h +++ b/src/Mod/TechDraw/Gui/QGISectionLine.h @@ -49,6 +49,7 @@ public: virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 ); + void setEnds(Base::Vector3d l1, Base::Vector3d l2); void setBounds(double x1,double y1,double x2,double y2); void setSymbol(char* sym); void setDirection(double xDir,double yDir); @@ -71,6 +72,9 @@ protected: void makeSymbolsISO(); void setTools(); int getPrefSectionStandard(); + void extensionEndsISO(); + void extensionEndsTrad(); + private: char* m_symbol; @@ -89,6 +93,12 @@ private: //QColor m_color; double m_extLen; // int m_sectionFormat; //0 = ASME, 1 = ISO + Base::Vector3d m_l1; //end of main section line + Base::Vector3d m_l2; //end of main section line + QPointF m_beginExt1; //start of extension line 1 + QPointF m_endExt1; //end of extension line 1 + QPointF m_beginExt2; //start of extension line 2 + QPointF m_endExt2; //end of extension line 1 }; } diff --git a/src/Mod/TechDraw/Gui/QGIViewPart.cpp b/src/Mod/TechDraw/Gui/QGIViewPart.cpp index 6454c0188a..f4e568cb11 100644 --- a/src/Mod/TechDraw/Gui/QGIViewPart.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewPart.cpp @@ -838,88 +838,31 @@ void QGIViewPart::drawSectionLine(TechDraw::DrawViewSection* viewSection, bool b sectionLine->setSectionStyle(vp->SectionLineStyle.getValue()); sectionLine->setSectionColor(vp->SectionLineColor.getValue().asValue()); - //TODO: handle oblique section lines? - //find smallest internal angle(normalDir,get?Dir()) and use -1*get?Dir() +/- angle - //Base::Vector3d normalDir = viewSection->SectionNormal.getValue(); - Base::Vector3d arrowDir(0,1,0); //for drawing only, not geom - Base::Vector3d lineDir(1,0,0); - bool horiz = false; - - //this is a hack we can use since we don't support oblique section lines yet. - //better solution will be need if oblique is ever implemented - double rot = viewPart->Rotation.getValue(); - bool switchWH = false; - if (TechDraw::DrawUtil::fpCompare(fabs(rot), 90.0)) { - switchWH = true; - } - - if (viewSection->SectionDirection.isValue("Right")) { - arrowDir = Base::Vector3d(1,0,0); - lineDir = Base::Vector3d(0,1,0); - } else if (viewSection->SectionDirection.isValue("Left")) { - arrowDir = Base::Vector3d(-1,0,0); - lineDir = Base::Vector3d(0,-1,0); - } else if (viewSection->SectionDirection.isValue("Up")) { - arrowDir = Base::Vector3d(0,1,0); - lineDir = Base::Vector3d(1,0,0); - horiz = true; - } else if (viewSection->SectionDirection.isValue("Down")) { - arrowDir = Base::Vector3d(0,-1,0); - lineDir = Base::Vector3d(-1,0,0); - horiz = true; - } - sectionLine->setDirection(arrowDir.x,arrowDir.y); - - //dvp is centered on centroid looking along dvp direction - //dvs is centered on SO looking along section normal - //dvp view origin is 000 + centroid - Base::Vector3d org = viewSection->SectionOrigin.getValue(); - Base::Vector3d cent = viewPart->getOriginalCentroid(); - Base::Vector3d adjOrg = org - cent; + //find the ends of the section line double scale = viewPart->getScale(); + std::pair sLineEnds = viewSection->sectionLineEnds(); + Base::Vector3d l1 = Rez::guiX(sLineEnds.first) * scale; + Base::Vector3d l2 = Rez::guiX(sLineEnds.second) * scale; - Base::Vector3d pAdjOrg = scale * viewPart->projectPoint(adjOrg); + //which way to the arrows point? + Base::Vector3d lineDir = l2 - l1; + lineDir.Normalize(); + Base::Vector3d normalDir = viewSection->SectionNormal.getValue(); + Base::Vector3d projNormal = viewPart->projectPoint(normalDir); + projNormal.Normalize(); + Base::Vector3d arrowDir = viewSection->SectionNormal.getValue(); + arrowDir = - viewPart->projectPoint(arrowDir); //arrows point reverse of sectionNormal(extrusion dir) + sectionLine->setDirection(arrowDir.x, -arrowDir.y); //invert Y - //now project pOrg onto arrowDir - Base::Vector3d displace; - displace.ProjectToLine(pAdjOrg, arrowDir); - Base::Vector3d offset = pAdjOrg + displace; + //make the section line a little longer + double fudge = Rez::guiX(2.0 * Preferences::dimFontSizeMM()); + sectionLine->setEnds(l1 - lineDir * fudge, + l2 + lineDir * fudge); -// makeMark(0.0, 0.0); //red -// makeMark(Rez::guiX(offset.x), -// Rez::guiX(offset.y), -// Qt::green); - - sectionLine->setPos(Rez::guiX(offset.x),Rez::guiX(offset.y)); - double sectionSpan; - double sectionFudge = Rez::guiX(10.0); - double xVal, yVal; -// double fontSize = getPrefFontSize(); -// double fontSize = getDimFontSize(); - double fontSize = Preferences::dimFontSizeMM(); - if (horiz) { - double width = Rez::guiX(viewPart->getBoxX()); - double height = Rez::guiX(viewPart->getBoxY()); - if (switchWH) { - sectionSpan = height + sectionFudge; - } else { - sectionSpan = width + sectionFudge; - } - xVal = sectionSpan / 2.0; - yVal = 0.0; - } else { - double width = Rez::guiX(viewPart->getBoxX()); - double height = Rez::guiX(viewPart->getBoxY()); - if (switchWH) { - sectionSpan = width + sectionFudge; - } else { - sectionSpan = height + sectionFudge; - } - xVal = 0.0; - yVal = sectionSpan / 2.0; - } - sectionLine->setBounds(-xVal,-yVal,xVal,yVal); + //set the general parameters + sectionLine->setPos(0.0, 0.0); sectionLine->setWidth(Rez::guiX(vp->LineWidth.getValue())); + double fontSize = Preferences::dimFontSizeMM(); sectionLine->setFont(m_font, fontSize); sectionLine->setZValue(ZVALUE::SECTIONLINE); sectionLine->setRotation(viewPart->Rotation.getValue());