diff --git a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp index 3c7a73225f3d..99dd0024f6f8 100644 --- a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp @@ -530,57 +530,64 @@ void QGIViewDimension::draw() } else if(strcmp(dimType, "Diameter") == 0) { // terminology: Dimension Text, Dimension Line(s), Extension Lines, Arrowheads - // was datumLabel, datum line/parallel line, perpendicular line, arw - Base::Vector3d arrow1Tip, arrow2Tip, dirDimLine; //was p1,p2,dir + Base::Vector3d arrow1Tip, arrow2Tip; + Base::Vector3d arrow1Tail, arrow2Tail; + Base::Vector3d arrow1Dir,arrow2Dir; double radius; Base::Vector3d pointOnCurve,curveCenter; + Base::Vector3d startExt1,endExt1,startExt2,endExt2; arcPoints pts = dim->getArcPoints(); bool isArc = pts.isArc; radius = Rez::guiX(pts.radius); curveCenter = Rez::guiX(pts.center); pointOnCurve = Rez::guiX(pts.onCurve.first); - - // Note Bounding Box size is not the same width or height as text (only used for finding center) - float bbX = datumLabel->boundingRect().width(); - float bbY = datumLabel->boundingRect().height(); - - dirDimLine = (lblCenter - curveCenter).Normalize(); //if lblCenter == curveCenter, this is (0,0,0)?? - if (fabs(dirDimLine.Length()) < (Precision::Confusion())) { - dirDimLine = Base::Vector3d(-1.0,0.0,0.0); + + Base::Vector3d startDist,endDist,dirDim; + startDist = Rez::guiX(pts.onCurve.first); + endDist = Rez::guiX(pts.onCurve.second); + dirDim = endDist - startDist; + if (fabs(dirDim.Length()) < Precision::Confusion()) { + dirDim = Base::Vector3d(1.0,0.0,0.0); } + dirDim.Normalize(); + Base::Vector3d fauxCenter = lblCenter; - //this is for inner placement only? recalced for outer? - arrow1Tip = curveCenter - dirDimLine * radius; //endpoint of diameter arrowhead1 - arrow2Tip = curveCenter + dirDimLine * radius; //endpoint of diameter arrowhead2 + //default arrow endpoints + arrow1Tip = curveCenter - dirDim * radius; + arrow2Tip = curveCenter + dirDim * radius; + arrow1Tail = curveCenter; + arrow2Tail = curveCenter; QFontMetrics fm(datumLabel->font()); + int textWidth = fm.width(labelText); + int charWidth = fm.width(QString::fromLatin1("M")); //full width character - int w = fm.width(labelText); - //int h = fm.height(); - - margin = Rez::guiX(5.f); - - // Calculate the dimension line endpoints - // recalced for vert & horizontal snap & inner placement. not used for nosnap outer? - Base::Vector3d dLine1Tail = lblCenter - dirDimLine * (margin + w / 2); //position of tail of 1st dimension line - Base::Vector3d dLine2Tail = lblCenter + dirDimLine * (margin + w / 2); + double gapMargin = Rez::guiX(4.f); + margin = Rez::guiX(2.f); + float scaler = 1.; + double tip = (margin * scaler); + double gap = (gapMargin * scaler); //sb % of radius? + //offset of dimLine from dimText + double offsetFudge = 2.0; + double vertOffset = 1.0 * Rez::guiX(vp->Fontsize.getValue()) + offsetFudge; + double horizOffset = 1.0 * (textWidth/2.0) + (0.5 * charWidth) + offsetFudge; //a bit tight w/o more fudge bool outerPlacement = false; if ((lblCenter-curveCenter).Length() > radius) { //label is outside circle outerPlacement = true; } - // Reset transformation origin for datum label +// // Note Bounding Box size is not the same width or height as text (only used for finding center) + float bbX = datumLabel->boundingRect().width(); + float bbY = datumLabel->boundingRect().height(); datumLabel->setTransformOriginPoint(bbX / 2, bbY /2); int posMode = NoSnap; + bool isLeader = false; QPainterPath path; - if(outerPlacement) { - // Select whether to snap vertically or hoziontally given tolerance - Base::Vector3d v = (lblCenter-arrow1Tip); - + Base::Vector3d v = (lblCenter - curveCenter); double angle = atan2(v.y, v.x); double tolerance = 15.0; //deg @@ -594,141 +601,169 @@ void QGIViewDimension::draw() } if(posMode == VerticalSnap) { - float tip = (lblCenter.y > curveCenter.y) ? margin: -margin; - //tip *= 0.5; + if (lblCenter.y > curveCenter.y) { + tip = tip; + gap = gap; + fauxCenter = Base::Vector3d(lblCenter.x,lblCenter.y + vertOffset,lblCenter.z); + } else { + tip = -tip; + gap = -gap; + fauxCenter = Base::Vector3d(lblCenter.x,lblCenter.y + vertOffset,lblCenter.z); + } arrow1Tip.x = curveCenter.x - radius; //to left, on circle cl - arrow1Tip.y = lblCenter.y; + arrow1Tip.y = fauxCenter.y; + arrow1Tail.x = curveCenter.x; + arrow1Tail.y = arrow1Tip.y; + arrow1Dir = (arrow1Tip - arrow1Tail).Normalize(); + path.moveTo(arrow1Tail.x, arrow1Tail.y); + path.lineTo(arrow1Tip.x, arrow1Tip.y); arrow2Tip.x = curveCenter.x + radius; - arrow2Tip.y = lblCenter.y; - - dLine1Tail = lblCenter; - dLine1Tail.x -= (margin + w / 2); //to left, on label cl + arrow2Tip.y = fauxCenter.y; + arrow2Tail.x = curveCenter.x; + arrow2Tail.y = arrow2Tip.y; + arrow2Dir = (arrow2Tip - arrow2Tail).Normalize(); + path.moveTo(arrow2Tail.x, arrow2Tail.y); + path.lineTo(arrow2Tip.x, arrow2Tip.y); - dLine2Tail = lblCenter; - dLine2Tail.x += (margin + w / 2); + startExt1.x = curveCenter.x - radius; + startExt1.y = curveCenter.y + gap; + endExt1.x = startExt1.x; + endExt1.y = fauxCenter.y + tip; - // Extension line 1 - path.moveTo(curveCenter.x - radius, curveCenter.y); - path.lineTo(arrow1Tip.x, arrow1Tip.y + tip); + startExt2.x = curveCenter.x + radius; + startExt2.y = curveCenter.y + gap; + endExt2.x = startExt2.x; + endExt2.y = fauxCenter.y + tip; - path.moveTo(arrow1Tip.x, arrow1Tip.y); //dimension line, not arrowhead - path.lineTo(dLine1Tail.x, dLine1Tail.y); + path.moveTo(startExt1.x, startExt1.y); + path.lineTo(endExt1.x, endExt1.y); - // Extension line 2 - path.moveTo(curveCenter.x + radius, curveCenter.y); - path.lineTo(arrow2Tip.x, arrow2Tip.y + tip); - - path.moveTo(dLine2Tail.x, dLine2Tail.y); - path.lineTo(arrow2Tip.x, arrow2Tip.y); + path.moveTo(startExt2.x, startExt2.y); + path.lineTo(endExt2.x, endExt2.y); datumLabel->setRotation(0.); } else if(posMode == HorizontalSnap) { - // Snapped Horizontally - - float tip = (lblCenter.x > curveCenter.x) ? margin: -margin; - //tip *= 0.5; + if (lblCenter.x > curveCenter.x) { + tip = tip; + gap = gap; + fauxCenter = Base::Vector3d(lblCenter.x - horizOffset,lblCenter.y,lblCenter.z); + } else { + tip = -tip; + gap = -gap; + fauxCenter = Base::Vector3d(lblCenter.x + horizOffset,lblCenter.y,lblCenter.z); + } + arrow1Tip.x = fauxCenter.x; arrow1Tip.y = curveCenter.y - radius; - arrow1Tip.x = lblCenter.x; + arrow1Tail.x = arrow1Tip.x; + arrow1Tail.y = curveCenter.y; + arrow1Dir = (arrow1Tip - arrow1Tail).Normalize(); + path.moveTo(arrow1Tail.x, arrow1Tail.y); + path.lineTo(arrow1Tip.x, arrow1Tip.y); + arrow2Tip.x = fauxCenter.x; arrow2Tip.y = curveCenter.y + radius; - arrow2Tip.x = lblCenter.x; - - dLine1Tail = lblCenter; - dLine1Tail.y -= (margin + w / 2); - - dLine2Tail = lblCenter; - dLine2Tail.y += (margin + w / 2); + arrow2Tail.x = arrow2Tip.x; + arrow2Tail.y = curveCenter.y; + arrow2Dir = (arrow2Tip - arrow2Tail).Normalize(); + path.moveTo(arrow2Tail.x, arrow2Tail.y); + path.lineTo(arrow2Tip.x, arrow2Tip.y); - // Extension lines - path.moveTo(curveCenter.x, curveCenter.y - radius); - path.lineTo(arrow1Tip.x + tip, arrow1Tip.y); + startExt1.x = curveCenter.x + gap; + startExt1.y = curveCenter.y - radius; + endExt1.x = fauxCenter.x + tip; + endExt1.y = startExt1.y; - path.moveTo(arrow1Tip.x, arrow1Tip.y); - path.lineTo(dLine1Tail.x, dLine1Tail.y); + startExt2.x = curveCenter.x + gap; + startExt2.y = curveCenter.y + radius; + endExt2.x = fauxCenter.x + tip; + endExt2.y = startExt2.y; - // Extension lines - path.moveTo(curveCenter.x, curveCenter.y + radius); - path.lineTo(arrow2Tip.x + tip, arrow2Tip.y); + path.moveTo(startExt1.x, startExt1.y); + path.lineTo(endExt1.x, endExt1.y); - path.moveTo(dLine2Tail.x, dLine2Tail.y); - path.lineTo(arrow2Tip.x, arrow2Tip.y); + path.moveTo(startExt2.x, startExt2.y); + path.lineTo(endExt2.x, endExt2.y); - datumLabel->setRotation(-90.); + datumLabel->setRotation(0.0); } else { //outer placement, NoSnap - float tip = (margin + w / 2); // spacer + 0.5*lblText.width() tip is actually tail? - tip = (lblCenter.x < curveCenter.x) ? tip : -tip; //if label on left then tip is +ve (ie to right) - - arrow1Tip = lblCenter; //this tip is really tail(ie end near lblText) - arrow1Tip.x += tip; + isLeader = true; + float spacer = (margin + textWidth / 2); + spacer = (lblCenter.x < curveCenter.x) ? spacer : -spacer; + arrow1Tail = lblCenter; + arrow1Tail.x += spacer; - Base::Vector3d p3 = arrow1Tip; - p3.x += (lblCenter.x < curveCenter.x) ? margin : - margin; // p3 is a little farther away from lblText towards curveCenter in X + Base::Vector3d kinkPoint = arrow1Tail; + kinkPoint.x += (lblCenter.x < curveCenter.x) ? margin : - margin; - arrow2Tip = curveCenter + (p3 - curveCenter).Normalize() * radius; //point on curve aimed just short of label text + arrow1Tip = curveCenter + (kinkPoint - curveCenter).Normalize() * radius; - path.moveTo(arrow1Tip.x, arrow1Tip.y); - path.lineTo(p3[0], p3[1]); - - path.lineTo(arrow2Tip.x, arrow2Tip.y); + path.moveTo(arrow1Tail.x, arrow1Tail.y); + path.lineTo(kinkPoint.x, kinkPoint.y); + path.lineTo(arrow1Tip.x, arrow1Tip.y); + arrow1Dir = (arrow1Tip - kinkPoint).Normalize(); datumLabel->setRotation(0.); } } else { //NOT outerplacement ie dimLines are inside circle //text always rightside up inside circle datumLabel->setRotation(0); - dLine1Tail = curveCenter - dirDimLine * margin; - dLine2Tail = curveCenter + dirDimLine * margin; - - path.moveTo(arrow1Tip.x, arrow1Tip.y); - path.lineTo(dLine1Tail.x, dLine1Tail.y); - - path.moveTo(dLine2Tail.x, dLine2Tail.y); + dirDim = (lblCenter - curveCenter).Normalize(); + if (fabs(dirDim.Length()) < (Precision::Confusion())) { + dirDim = Base::Vector3d(-1.0,0.0,0.0); + } + + arrow1Tip = curveCenter - dirDim * radius; + arrow1Tail = curveCenter; + arrow1Dir = (arrow1Tip - arrow1Tail).Normalize(); + arrow2Tip = curveCenter + dirDim * radius; + arrow2Tail = curveCenter; + arrow2Dir = (arrow2Tip - arrow2Tail).Normalize(); + + path.moveTo(arrow1Tail.x, arrow1Tail.y); + path.lineTo(arrow1Tip.x, arrow1Tip.y); + + path.moveTo(arrow2Tail.x, arrow2Tail.y); path.lineTo(arrow2Tip.x, arrow2Tip.y); } aHead1->setStyle(QGIArrow::getPrefArrowStyle()); aHead1->setSize(QGIArrow::getPrefArrowSize()); - aHead1->draw(); - aHead2->flip(true); - aHead2->setStyle(QGIArrow::getPrefArrowStyle()); - aHead2->setSize(QGIArrow::getPrefArrowSize()); - aHead2->draw(); - - float arAngle = atan2(dirDimLine.y, dirDimLine.x) * 180 / M_PI; - aHead2->show(); + if (!isLeader) { + aHead2->setStyle(QGIArrow::getPrefArrowStyle()); + aHead2->setSize(QGIArrow::getPrefArrowSize()); + } //handle partial arc weird cases + //TODO: does anybody dimension Arcs with Diameter? doesn't Radius make more sense? Base::Vector3d dLineStart; Base::Vector3d kinkPoint; - margin = Rez::guiX(5.f); //space around label - double kinkLength = Rez::guiX(5.0); //sb % of horizontal dist(lblCenter,curveCenter)??? + margin = Rez::guiX(5.f); + double kinkLength = Rez::guiX(5.0); //sb % of horizontal dist(lblCenter,curveCenter)??? + QPainterPath arcPath; if (isArc) { - - aHead2->hide(); - aHead1->flip(true); - aHead1->draw(); + if (lblCenter.x > curveCenter.x) { // label to right of vert c/l + tip = tip; + gap = gap; + fauxCenter = Base::Vector3d(lblCenter.x - horizOffset,lblCenter.y,lblCenter.z); + kinkPoint = Base::Vector3d(fauxCenter.x - kinkLength,fauxCenter.y,fauxCenter.z); + } else { + tip = -tip; + gap = -gap; + fauxCenter = Base::Vector3d(lblCenter.x + horizOffset,lblCenter.y,lblCenter.z); + kinkPoint = Base::Vector3d(fauxCenter.x + kinkLength,fauxCenter.y,fauxCenter.z); + } + dirDim = (kinkPoint - curveCenter).Normalize(); + pointOnCurve = curveCenter + (dirDim * radius); Base::Vector3d startPt = Rez::guiX(pts.arcEnds.first); Base::Vector3d endPt = Rez::guiX(pts.arcEnds.second); - kinkLength = (lblCenter.x < curveCenter.x) ? kinkLength : -kinkLength; - dirDimLine = lblCenter - curveCenter; - dirDimLine.Normalize(); - - Base::Vector3d labelEndDir(1.0,0.0,0.0); - if (lblCenter.x > pointOnCurve.x) { //label is to right of point - labelEndDir = -1.0 * labelEndDir; - } - dLineStart = lblCenter + labelEndDir * (margin + w / 2); - kinkPoint.y = dLineStart.y; - kinkPoint.x = dLineStart.x + kinkLength; - pointOnCurve = curveCenter + dirDimLine * radius; - if (!dim->leaderIntersectsArc(Rez::appX(dLineStart),Rez::appX(pointOnCurve))) { //keep pathological case within arc + if (!dim->leaderIntersectsArc(Rez::appX(kinkPoint),Rez::appX(pointOnCurve))) { //keep point within arc if ((pointOnCurve - endPt).Length() < (pointOnCurve - startPt).Length()) { if (!pts.arcCW ) { pointOnCurve = endPt; @@ -743,42 +778,54 @@ void QGIViewDimension::draw() } } } - Base::Vector3d arVector = (kinkPoint - pointOnCurve); - arVector.Normalize(); - arAngle = atan2(arVector.y, arVector.x) * 180 / M_PI; - path = QPainterPath(); - path.moveTo(dLineStart.x,dLineStart.y); - path.lineTo(kinkPoint.x,kinkPoint.y); - path.lineTo(pointOnCurve.x,pointOnCurve.y); + arcPath.moveTo(fauxCenter.x,fauxCenter.y); + arcPath.lineTo(kinkPoint.x,kinkPoint.y); + arcPath.lineTo(pointOnCurve.x,pointOnCurve.y); + arrow1Dir = (pointOnCurve - kinkPoint).Normalize(); datumLabel->setRotation(0.); } dimLines->setPath(path); if (isArc) { + dimLines->setPath(arcPath); aHead1->setPos(pointOnCurve.x, pointOnCurve.y); - aHead1->setRotation(arAngle); + aHead1->setDirMode(true); + aHead1->setDirection(arrow1Dir); + aHead1->draw(); + aHead1->show(); aHead2->hide(); } else if(outerPlacement) { - if(posMode > NoSnap) { - aHead1->setPos(arrow2Tip.x, arrow2Tip.y); //arrow 1's endpoint is arrow2Tip!? - aHead2->setPos(arrow1Tip.x, arrow1Tip.y); - aHead1->setRotation((posMode == HorizontalSnap) ? 90 : 0); - aHead2->setRotation((posMode == HorizontalSnap) ? 90 : 0); - } else { - Base::Vector3d vec = (arrow2Tip - curveCenter).Normalize(); - float arAngle = atan2(-vec.y, -vec.x) * 180 / M_PI; - aHead1->setPos(arrow2Tip.x, arrow2Tip.y); - aHead1->setRotation(arAngle); - aHead2->hide(); //only 1 arrowhead for NoSnap + outerplacement (ie a leader) + if(posMode > NoSnap) { // Horizontal or Vertical snap + aHead1->setPos(arrow1Tip.x, arrow1Tip.y); + aHead1->setDirMode(true); + aHead1->setDirection(arrow1Dir); + aHead1->draw(); + aHead1->show(); + aHead2->setPos(arrow2Tip.x, arrow2Tip.y); + aHead2->setDirMode(true); + aHead2->setDirection(arrow2Dir); + aHead2->draw(); + aHead2->show(); + } else { //leader stye + aHead1->setPos(arrow1Tip.x, arrow1Tip.y); + aHead1->setDirMode(true); + aHead1->setDirection(arrow1Dir); + aHead1->draw(); + aHead1->show(); + aHead2->hide(); //only 1 arrowhead for NoSnap + outerplacement (ie a leader) } - } else { - aHead1->setRotation(arAngle); - aHead2->setRotation(arAngle); - - aHead1->setPos(arrow2Tip.x, arrow2Tip.y); + } else { //inner placement + aHead1->setPos(arrow1Tip.x, arrow1Tip.y); + aHead1->setDirMode(true); + aHead1->setDirection(arrow1Dir); + aHead1->draw(); + aHead1->show(); + aHead2->setPos(arrow2Tip.x, arrow2Tip.y); + aHead2->setDirMode(true); + aHead2->setDirection(arrow2Dir); + aHead2->draw(); aHead2->show(); - aHead2->setPos(arrow1Tip.x, arrow1Tip.y); } // if (dim->CentreLines.getValue()) {