diff --git a/src/Mod/TechDraw/Gui/QGIArrow.cpp b/src/Mod/TechDraw/Gui/QGIArrow.cpp index 8c56c6ede3..001ef5739b 100644 --- a/src/Mod/TechDraw/Gui/QGIArrow.cpp +++ b/src/Mod/TechDraw/Gui/QGIArrow.cpp @@ -45,10 +45,10 @@ QGIArrow::QGIArrow() : m_fill(Qt::SolidPattern), m_size(5.0), m_style(0), + m_flipped(false), m_dirMode(false), m_dir(Base::Vector3d(1.0,0.0,0.0)) { - isFlipped = false; m_brush.setStyle(m_fill); setCacheMode(QGraphicsItem::NoCache); @@ -57,43 +57,38 @@ QGIArrow::QGIArrow() : setFlag(QGraphicsItem::ItemIsMovable, false); } - -void QGIArrow::flip(bool state) { - isFlipped = state; -} - void QGIArrow::draw() { QPainterPath path; if (m_style == 0) { if (m_dirMode) { path = makeFilledTriangle(getDirection(), m_size,m_size/6.0); } else { - path = makeFilledTriangle(m_size,m_size/6.0,isFlipped); //"arrow l/w sb 3/1" ?? + path = makeFilledTriangle(m_size,m_size/6.0,isFlipped()); //"arrow l/w sb 3/1" ?? } } else if (m_style == 1) { if (m_dirMode) { path = makeOpenArrow(getDirection(), m_size,m_size/3.0); //broad arrow? } else { - path = makeOpenArrow(m_size,m_size/3.0,isFlipped); + path = makeOpenArrow(m_size,m_size/3.0,isFlipped()); } } else if (m_style == 2) { if (m_dirMode) { path = makeHashMark(getDirection(), m_size/2.0,m_size/2.0); //big enough? } else { - path = makeHashMark(m_size/2.0,m_size/2.0,isFlipped); //big enough? + path = makeHashMark(m_size/2.0,m_size/2.0,isFlipped()); //big enough? } } else if (m_style == 3) { - path = makeDot(m_size/2.0,m_size/2.0,isFlipped); + path = makeDot(m_size/2.0,m_size/2.0,isFlipped()); } else if (m_style == 4) { - path = makeOpenDot(m_size/2.0,m_size/2.0,isFlipped); + path = makeOpenDot(m_size/2.0,m_size/2.0,isFlipped()); } else if (m_style == 5) { if (m_dirMode) { path = makeForkArrow(getDirection(), m_size/2.0,m_size/2.0); //big enough? } else { - path = makeForkArrow(m_size/2.0,m_size/2.0,isFlipped); //big enough? + path = makeForkArrow(m_size/2.0,m_size/2.0,isFlipped()); //big enough? } } else { - path = makeFilledTriangle(m_size,m_size/6.0,isFlipped); //sb a question mark or ??? + path = makeFilledTriangle(m_size,m_size/6.0,isFlipped()); //sb a question mark or ??? } setPath(path); } diff --git a/src/Mod/TechDraw/Gui/QGIArrow.h b/src/Mod/TechDraw/Gui/QGIArrow.h index 7c5215a1d7..9074a4b7ab 100644 --- a/src/Mod/TechDraw/Gui/QGIArrow.h +++ b/src/Mod/TechDraw/Gui/QGIArrow.h @@ -46,15 +46,18 @@ public: public: void draw(); - void flip(bool state); + bool isFlipped() { return m_flipped; } + void setFlipped(bool flipped) { m_flipped = flipped; } + void flip() { m_flipped = !m_flipped; } double getSize() { return m_size; } void setSize(double s); int getStyle() { return m_style; } void setStyle(int s) { m_style = s; } bool getDirMode() { return m_dirMode; } void setDirMode(bool b) { m_dirMode = b; } - Base::Vector3d getDirection(void) { return m_dir; } + Base::Vector3d getDirection(void) { return m_flipped ? -m_dir : m_dir; } void setDirection(Base::Vector3d v) { m_dir = v; } + void setDirection(double angle) { m_dir = Base::Vector3d(cos(angle), sin(angle), 0.0); } static int getPrefArrowStyle(); static double getPrefArrowSize(); static double getOverlapAdjust(int style, double size); @@ -78,7 +81,7 @@ private: Qt::BrushStyle m_fill; double m_size; int m_style; - bool isFlipped; + bool m_flipped; bool m_dirMode; Base::Vector3d m_dir; }; diff --git a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp index 7eef5d5d0a..9964af89fd 100644 --- a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp @@ -69,6 +69,10 @@ #include "ViewProviderDimension.h" #include "DrawGuiUtil.h" +#ifndef M_2PI + #define M_2PI 6.283185307179586476925287 +#endif + //TODO: hide the Qt coord system (+y down). using namespace TechDraw; @@ -182,8 +186,7 @@ void QGIDatumLabel::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt QStyleOptionGraphicsItem myOption(*option); myOption.state &= ~QStyle::State_Selected; -// painter->drawRect(boundingRect()); //good for debugging - + //painter->drawRect(boundingRect()); //good for debugging } void QGIDatumLabel::setPosFromCenter(const double &xCenter, const double &yCenter) @@ -1171,127 +1174,7 @@ void QGIViewDimension::draw() // dim->getViewPart()->addVertex(curveCenter,true); // } } else if(strcmp(dimType, "Radius") == 0) { - // preferred terminology: Dimension Text, Dimension Line(s), Extension Lines, Arrowheads - // radius gets 1 dimension line from the dimension text to a point on the curve - Base::Vector3d pointOnCurve,curveCenter; - double radius; - arcPoints pts = dim->getArcPoints(); - bool isArc = pts.isArc; - radius = Rez::guiX(pts.radius); - curveCenter = Rez::guiX(pts.center); - pointOnCurve = Rez::guiX(pts.onCurve.first); - QRectF mappedRect = mapRectFromItem(datumLabel, datumLabel->boundingRect()); - lblCenter = Base::Vector3d(mappedRect.center().x(), mappedRect.center().y(), 0.0); - - // 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); - datumLabel->setRotation(0.0); //label is always right side up & horizontal - - //if inside the arc (len(DimLine < radius)) arrow goes from center to edge away from label - //if outside the arc arrow kinks, then goes to edge nearest label - bool outerPlacement = false; - if ((lblCenter - curveCenter).Length() > radius) { //label is outside circle - outerPlacement = true; - } - - Base::Vector3d dirDimLine = (lblCenter - curveCenter).Normalize(); - if (fabs(dirDimLine.Length()) < (Precision::Confusion())) { - dirDimLine = Base::Vector3d(-1.0,0.0,0.0); - } -// Base::Vector3d adjustDir = dirDimLine; //adjust line lengths for arrowheads - double dimLineAdjust = Rez::guiX(QGIArrow::getOverlapAdjust(QGIArrow::getPrefArrowStyle(), - QGIArrow::getPrefArrowSize())); - - - Base::Vector3d dLineStart; - Base::Vector3d dLineEnd; //?? radius draws line from text to curve?? (diam is curve to text!) - Base::Vector3d kinkPoint; - margin = Rez::guiX(5.f); //space around label - double kinkLength = Rez::guiX(5.0); //sb % of horizontal dist(lblCenter,curveCenter)??? - if (outerPlacement) { - double offset = getDefaultTextHorizontalOffset(lblCenter.x > curveCenter.x); - dLineStart.y = lblCenter.y; - dLineStart.x = lblCenter.x + offset; //start at right or left of label - kinkLength = (lblCenter.x < curveCenter.x) ? kinkLength : -kinkLength; - kinkPoint.y = dLineStart.y; - kinkPoint.x = dLineStart.x + kinkLength; - pointOnCurve = curveCenter + (kinkPoint - curveCenter).Normalize() * radius; - dLineEnd = pointOnCurve + (kinkPoint - curveCenter).Normalize() * dimLineAdjust; - if ((kinkPoint - curveCenter).Length() < radius) { - dirDimLine = (curveCenter - kinkPoint).Normalize(); - } else { - dirDimLine = (kinkPoint - curveCenter).Normalize(); - } - } else { - dLineStart = curveCenter - dirDimLine * margin; //just beyond centerpoint - pointOnCurve = curveCenter - dirDimLine * radius; - dLineEnd = pointOnCurve + dirDimLine * dimLineAdjust; - kinkPoint = dLineStart; //no kink - } - - //handle partial arc weird cases - if (isArc) { - Base::Vector3d midPt = Rez::guiX(pts.midArc); - Base::Vector3d startPt = Rez::guiX(pts.arcEnds.first); - Base::Vector3d endPt = Rez::guiX(pts.arcEnds.second); - if (outerPlacement && - !dim->leaderIntersectsArc(Rez::appX(curveCenter),Rez::appX(kinkPoint))) { //keep pathological case within arc - pointOnCurve = midPt; - } else if (!outerPlacement) { - if ((midPt - lblCenter).Length() > (midPt - curveCenter).Length()) { //label is farther than center - dirDimLine = dirDimLine * -1; - } - dLineStart = curveCenter + dirDimLine * margin; - pointOnCurve = curveCenter + dirDimLine * radius; - dLineEnd = pointOnCurve - dirDimLine * dimLineAdjust; - kinkPoint = dLineStart; - if (!dim->leaderIntersectsArc(Rez::appX(dLineStart),Rez::appX(pointOnCurve))) { //keep pathological case within arc - if ((pointOnCurve - endPt).Length() < (pointOnCurve - startPt).Length()) { - if (!pts.arcCW ) { - pointOnCurve = endPt; - } else { - pointOnCurve = startPt; - } - } else { - if (!pts.arcCW ) { - pointOnCurve = startPt; - } else { - pointOnCurve = endPt; - } - } - dLineStart = curveCenter + (pointOnCurve - curveCenter).Normalize() * margin; - dLineEnd = pointOnCurve - dirDimLine * dimLineAdjust; - kinkPoint = dLineStart; - } - } - } - - QPainterPath dLinePath; //radius dimension line path - dLinePath.moveTo(dLineStart.x, dLineStart.y); - dLinePath.lineTo(kinkPoint.x, kinkPoint.y); - dLinePath.lineTo(dLineEnd.x, dLineEnd.y); - - dimLines->setPath(dLinePath); - //NOTE: in this case aHead1->dirMode is false and Qt rotation is used to point arrowhead - aHead1->setStyle(QGIArrow::getPrefArrowStyle()); - aHead1->setSize(QGIArrow::getPrefArrowSize()); - aHead1->draw(); - - Base::Vector3d ar1Pos = pointOnCurve; - Base::Vector3d dirArrowLine = (pointOnCurve - kinkPoint).Normalize(); - float arAngle = atan2(dirArrowLine.y, dirArrowLine.x) * 180 / M_PI; - - aHead1->setPos(ar1Pos.x, ar1Pos.y); - aHead1->setRotation(arAngle); - aHead1->show(); - aHead2->hide(); -// if (dim->CentreLines.getValue()) { -// curveCenterMark->setPos(curveCenter.x,curveCenter.y); -// centerMark->show(); -// dim->getViewPart()->addVertex(curveCenter,true); -// } + drawRadius(dim, vp); } else if( (strcmp(dimType, "Angle") == 0) || (strcmp(dimType, "Angle3Pt") == 0)) { anglePoints pts = dim->getAnglePoints(); @@ -1408,7 +1291,7 @@ void QGIViewDimension::draw() dimLines->setPath(path); //NOTE: arrowheads are dirMode(false) - aHead1->flip(true); + aHead1->setFlipped(true); aHead1->setStyle(QGIArrow::getPrefArrowStyle()); aHead1->setSize(QGIArrow::getPrefArrowSize()); aHead1->draw(); @@ -1489,6 +1372,281 @@ void QGIViewDimension::draw() } } +int QGIViewDimension::classifyPointToArcPosition(double pointDistance, double pointAngle, + double radius, double startAngle, double endAngle, bool clockwise) const +{ + if (angleWithinSector(pointAngle, startAngle, endAngle, clockwise)) { + return pointDistance > radius ? OUTER_SECTOR : INNER_SECTOR; + } + + if (angleWithinSector(addAngles(pointAngle, M_PI), startAngle, endAngle, clockwise)) { + return OPPOSITE_SECTOR; + } + + return COMPLEMENT_SECTOR; +} + +double QGIViewDimension::computeLineAndLabelAngles(Base::Vector3d lineTarget, Base::Vector3d labelCenter, + double lineLabelDistance, double &lineAngle, double &labelAngle) const +{ + // By default horizontal line and no label rotation + lineAngle = 0.0; + labelAngle = 0.0; + + Base::Vector3d rawDirection(labelCenter - lineTarget); + double rawDistance = rawDirection.Length(); + if (rawDistance < Precision::Confusion()) { // Almost single point, can't tell + return 0.0; + } + + double rawAngle = atan2(rawDirection.y, rawDirection.x); + lineAngle = rawAngle; + + // If we are too close to the line origin, no further adjustments + if (lineLabelDistance >= rawDistance) { + return 0.0; + } + + // Rotate the line by angle between the label rectangle center and label bottom side center + double devAngle = getStandardLinePlacement(rawAngle)*asin(lineLabelDistance/rawDistance); + lineAngle = addAngles(lineAngle, devAngle); + + labelAngle = devAngle > 0.0 ? lineAngle : addAngles(lineAngle, M_PI); + + return devAngle; +} + +Base::Vector3d QGIViewDimension::computeLineOriginPoint(Base::Vector3d lineTarget, double projectedLabelDistance, + double lineAngle, double labelWidth, double direction) const +{ + return lineTarget + (projectedLabelDistance + direction*(0.5*labelWidth + getDefaultReferenceLineOverhang())) + *Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0); +} + +void QGIViewDimension::drawRadius(TechDraw::DrawViewDimension *dimension, ViewProviderDimension *viewProvider) const +{ + // Preferred terminology according to ISO 129-1 for Radius: + // Dimensional Value, Leader Line, Reference Line, Terminator + + QPainterPath radiusPath; + aHead1->setFlipped(false); + + datumLabel->setRotation(0.0); + QRectF mappedRect = mapRectFromItem(datumLabel, datumLabel->boundingRect()); + Base::Vector3d labelCenter = Base::Vector3d(mappedRect.center().x(), mappedRect.center().y(), 0.0); + + arcPoints curvePoints = dimension->getArcPoints(); + + Base::Vector3d curveCenter = Rez::guiX(curvePoints.center); + double mappedRadius = Rez::guiX(curvePoints.radius); + double centerDistance = (labelCenter - curveCenter).Length(); + + double arcStartAngle; + double arcEndAngle; + bool arcClockwise; + if (curvePoints.isArc) { + arcStartAngle = atan2(curvePoints.arcEnds.first.y - curvePoints.center.y, + curvePoints.arcEnds.first.x - curvePoints.center.x); + arcEndAngle = atan2(curvePoints.arcEnds.second.y - curvePoints.center.y, + curvePoints.arcEnds.second.x - curvePoints.center.x); + arcClockwise = !curvePoints.arcCW; + } + else { // A circle arc covers the whole plane + arcStartAngle = -M_PI; + arcEndAngle = +M_PI; + arcClockwise = false; + } + + double labelAngle = 0.0; + Base::Vector3d arcPoint; + double lineAngle; + + if (viewProvider->TiltText.getValue()) { // We may rotate the label so no reference line is needed + double devAngle = computeLineAndLabelAngles(curveCenter, labelCenter, + getDefaultTextVerticalOffset(), lineAngle, labelAngle); + // Correct the label center distance projected on the leader line + centerDistance *= cos(devAngle); + + Base::Vector3d originPoint; + Base::Vector3d targetPoint; + switch (classifyPointToArcPosition(centerDistance, lineAngle, mappedRadius, + arcStartAngle, arcEndAngle, arcClockwise)) { + case INNER_SECTOR: { + // The label is placed within the arc sector angle, there's always point + // on the arc where the leader line can cross it perpendicularly + arcPoint = curveCenter + mappedRadius*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0); + + if (viewProvider->ExtendToCenter.getValue()) { // Start in the very center + originPoint = curveCenter; + } + else { // Start on the label side closer to the center + originPoint = computeLineOriginPoint(curveCenter, centerDistance, lineAngle, + mappedRect.width(), -1.0); + } + targetPoint = arcPoint; + break; + } + case OUTER_SECTOR: { + // Same situation as when on the inner side of sector + arcPoint = curveCenter + mappedRadius*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0); + aHead1->flip(); + + originPoint = computeLineOriginPoint(curveCenter, centerDistance, lineAngle, + mappedRect.width(), +1.0); + // If leader line shall not be extended to the center, start on the arc projection + targetPoint = viewProvider->ExtendToCenter.getValue() ? curveCenter : arcPoint; + break; + } + case OPPOSITE_SECTOR: { + // If the label is placed within the vertically opposite angle of the arc sector, + // the leader line passing through the arc center can mark a point on the arc + arcPoint = curveCenter - mappedRadius*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0); + aHead1->flip(); + + originPoint = computeLineOriginPoint(curveCenter, centerDistance, lineAngle, + mappedRect.width(), +1.0); + targetPoint = arcPoint; + break; + } + default: { + // Label outside both arc wedges + arcPoint = Rez::guiX(curvePoints.midArc); + aHead1->flip(); + devAngle = computeLineAndLabelAngles(arcPoint, labelCenter, + getDefaultTextVerticalOffset(), lineAngle, labelAngle); + centerDistance = (labelCenter - arcPoint).Length()*cos(devAngle); + + originPoint = computeLineOriginPoint(arcPoint, centerDistance, lineAngle, + mappedRect.width(), +1.0); + targetPoint = arcPoint; + break; + } + } + + // Draw only the leader line from start point to end point + radiusPath.moveTo(originPoint.x, originPoint.y); + radiusPath.lineTo(targetPoint.x, targetPoint.y); + } + else { // The dimensional value text must stay horizontal + Base::Vector3d leftJoint(mappedRect.left() - getDefaultReferenceLineOverhang(), + labelCenter.y + getDefaultTextVerticalOffset(), 0.0); + Base::Vector3d rightJoint(mappedRect.right() + getDefaultReferenceLineOverhang(), + labelCenter.y + getDefaultTextVerticalOffset(), 0.0); + + double leftAngle = atan2(leftJoint.y - curveCenter.y, leftJoint.x - curveCenter.x); + double rightAngle = atan2(rightJoint.y - curveCenter.y, rightJoint.x - curveCenter.x); + + int leftPosition = classifyPointToArcPosition((leftJoint - curveCenter).Length(), + leftAngle, mappedRadius, arcStartAngle, arcEndAngle, arcClockwise); + int rightPosition = classifyPointToArcPosition((rightJoint - curveCenter).Length(), + rightAngle, mappedRadius, arcStartAngle, arcEndAngle, arcClockwise); + + Base::Vector3d originPoint; + Base::Vector3d jointPoint; + Base::Vector3d targetPoint; + if (leftPosition >= OPPOSITE_SECTOR || rightPosition >= OPPOSITE_SECTOR) { + // At least from one of the reference line sides can run the leader line + // perpendicularly to the arc, i.e. in direction to the center + if (leftPosition >= OPPOSITE_SECTOR && rightPosition >= OPPOSITE_SECTOR) { + // Both are acceptable, so choose the more convenient one + double leftBend = leftPosition == INNER_SECTOR ? M_PI - fabs(leftAngle) : fabs(leftAngle); + double rightBend = rightPosition == INNER_SECTOR ? fabs(rightAngle) : M_PI - fabs(rightAngle); + + // If right leader line bends less or does not cross the dimensional value, + // use it by marking left point as outlayer + if (leftBend <= M_PI_2 || rightBend <= M_PI_2) { // At least one line is not crossing the text + if (rightBend < leftBend) { + leftPosition = COMPLEMENT_SECTOR; + } + } + else { + bool leftDown = leftPosition == INNER_SECTOR ? leftAngle > 0.0 : leftAngle < 0.0; + bool rightDown = rightPosition == INNER_SECTOR ? rightAngle > 0.0 : rightAngle < 0.0; + + if (leftDown == rightDown) { // Both lines go downwards or upwards + if (rightBend < leftBend) { + leftPosition = COMPLEMENT_SECTOR; + } + } + else if (rightDown) { + leftPosition = COMPLEMENT_SECTOR; + } + } + } + + int resultPosition; + if (leftPosition >= OPPOSITE_SECTOR) { + originPoint = rightJoint; + jointPoint = leftJoint; + lineAngle = leftAngle; + resultPosition = leftPosition; + } + else { + originPoint = leftJoint; + jointPoint = rightJoint; + lineAngle = rightAngle; + resultPosition = rightPosition; + } + + switch (resultPosition) { + case INNER_SECTOR: + arcPoint = curveCenter + mappedRadius*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0); + targetPoint = arcPoint; + break; + case OUTER_SECTOR: + arcPoint = curveCenter + mappedRadius*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0); + // If desired, extend the target point to the center + targetPoint = viewProvider->ExtendToCenter.getValue() ? curveCenter : arcPoint; + aHead1->flip(); + break; + case OPPOSITE_SECTOR: + arcPoint = curveCenter - mappedRadius*Base::Vector3d(cos(lineAngle), sin(lineAngle), 0.0); + targetPoint = arcPoint; + aHead1->flip(); + break; + } + } + else { // Both joint points lay outside the vertical angles + arcPoint = Rez::guiX(curvePoints.midArc); + + if (labelCenter.x >= arcPoint.x) { // Place the dimensional value right + originPoint = rightJoint; + jointPoint = leftJoint; + } + else { // Place the dimensional value left + originPoint = leftJoint; + jointPoint = rightJoint; + } + + targetPoint = arcPoint; + lineAngle = atan2(targetPoint.y - jointPoint.y, targetPoint.x - jointPoint.x); + } + + radiusPath.moveTo(originPoint.x, originPoint.y); + radiusPath.lineTo(jointPoint.x, jointPoint.y); + radiusPath.lineTo(targetPoint.x, targetPoint.y); + } + + datumLabel->setTransformOriginPoint(datumLabel->boundingRect().width()*0.5, + datumLabel->boundingRect().height()*0.5); + datumLabel->setRotation(labelAngle*180.0/M_PI); + + dimLines->setPath(radiusPath); + + aHead1->setPos(arcPoint.x, arcPoint.y); + aHead1->setDirMode(true); + aHead1->setDirection(lineAngle); + if (viewProvider->FlipArrowheads.getValue()) { + aHead1->flip(); + } + aHead1->setStyle(QGIArrow::getPrefArrowStyle()); + aHead1->setSize(QGIArrow::getPrefArrowSize()); + aHead1->draw(); + aHead1->show(); + + aHead2->hide(); +} + QColor QGIViewDimension::getNormalColor() { Base::Reference hGrp = App::GetApplication().GetUserParameter() @@ -1613,6 +1771,50 @@ double QGIViewDimension::getDefaultTextVerticalOffset() const return textMult*Rez::guiX(vp->Fontsize.getValue()) + TextOffsetFudge; } +double QGIViewDimension::getDefaultReferenceLineOverhang() const +{ + return 2.0*TextOffsetFudge; +} + +double QGIViewDimension::getStandardLinePlacement(double labelAngle) +{ + // According to ISO 129-1 Standard Figure 23, the bordering angle is 2/3 PI, resp. -1/3 PI + // As Qt Y axis points downwards, all signs are flipped + return labelAngle > +M_PI/3.0 || labelAngle < -2.0*M_PI/3.0 + ? -1.0 : +1.0; +} + +bool QGIViewDimension::angleWithinSector(double testAngle, double startAngle, double endAngle, bool clockwise) +{ + if (clockwise) { + std::swap(startAngle, endAngle); + } + + if (endAngle < startAngle) { + endAngle += M_2PI; + } + + if (testAngle < startAngle) { + testAngle += M_2PI; + } + + return testAngle <= endAngle; +} + +double QGIViewDimension::addAngles(double angle1, double angle2) +{ + angle1 += angle2; + + if (angle2 >= 0.0) { + if (angle1 > +M_PI) angle1 -= M_2PI; + return angle1; + } + else { + if (angle1 < -M_PI) angle1 += M_2PI; + return angle1; + } +} + //frame, border, caption are never shown in QGIVD, so shouldn't be in bRect QRectF QGIViewDimension::boundingRect() const { diff --git a/src/Mod/TechDraw/Gui/QGIViewDimension.h b/src/Mod/TechDraw/Gui/QGIViewDimension.h index 53f5fbc630..d95757d881 100644 --- a/src/Mod/TechDraw/Gui/QGIViewDimension.h +++ b/src/Mod/TechDraw/Gui/QGIViewDimension.h @@ -48,6 +48,7 @@ namespace TechDrawGui class QGIArrow; class QGIDimLines; class QGIViewDimension; +class ViewProviderDimension; class QGIDatumLabel : public QGraphicsObject { @@ -154,6 +155,20 @@ public Q_SLOTS: void updateDim(bool obtuse = false); protected: + + static const int INNER_SECTOR = 3; + static const int OUTER_SECTOR = 2; + static const int OPPOSITE_SECTOR = 1; + static const int COMPLEMENT_SECTOR = 0; + + int classifyPointToArcPosition(double pointDistance, double pointAngle, + double radius, double startAngle, double endAngle, bool clockwise) const; + double computeLineAndLabelAngles(Base::Vector3d lineTarget, Base::Vector3d labelCenter, + double lineLabelDistance, double &lineAngle, double &labelAngle) const; + Base::Vector3d computeLineOriginPoint(Base::Vector3d lineTarget, double projectedLabelDistance, + double lineAngle, double labelWidth, double direction) const; + + void drawRadius(TechDraw::DrawViewDimension *dimension, ViewProviderDimension *viewProvider) const; void draw() override; virtual QVariant itemChange( GraphicsItemChange change, const QVariant &value ) override; @@ -178,6 +193,11 @@ private: double getDefaultTextHorizontalOffset(bool toLeft) const; double getDefaultTextVerticalOffset() const; + double getDefaultReferenceLineOverhang() const; + + static double getStandardLinePlacement(double labelAngle); + static bool angleWithinSector(double testAngle, double startAngle, double endAngle, bool clockwise); + static double addAngles(double angle1, double angle2); }; } // namespace MDIViewPageGui diff --git a/src/Mod/TechDraw/Gui/ViewProviderDimension.cpp b/src/Mod/TechDraw/Gui/ViewProviderDimension.cpp index 3f5ad9ed3e..6fd65c7576 100644 --- a/src/Mod/TechDraw/Gui/ViewProviderDimension.cpp +++ b/src/Mod/TechDraw/Gui/ViewProviderDimension.cpp @@ -79,8 +79,9 @@ ViewProviderDimension::ViewProviderDimension() fcColor.setPackedValue(hGrp->GetUnsigned("Color", 0x00000000)); ADD_PROPERTY_TYPE(Color,(fcColor),group,App::Prop_None,"The color of the Dimension"); - ADD_PROPERTY_TYPE(FlipArrowheads ,(false),group,App::Prop_None,"Reverse the normal direction of arrowheads on dimline"); - + ADD_PROPERTY_TYPE(FlipArrowheads, (false), group, App::Prop_None,"Reverse the normal direction of arrowheads on dimline"); + ADD_PROPERTY_TYPE(TiltText, (true), group, App::Prop_None,"Rotate the text label so it is parallel with dimline"); + ADD_PROPERTY_TYPE(ExtendToCenter, (true), group, App::Prop_None,"Prolong the leader line right upto the center point"); } ViewProviderDimension::~ViewProviderDimension() @@ -131,7 +132,9 @@ void ViewProviderDimension::onChanged(const App::Property* p) if ((p == &Font) || (p == &Fontsize) || (p == &LineWidth) || - (p == &FlipArrowheads)) { + (p == &FlipArrowheads) || + (p == &TiltText) || + (p == &ExtendToCenter)) { QGIView* qgiv = getQView(); if (qgiv) { qgiv->updateView(true); diff --git a/src/Mod/TechDraw/Gui/ViewProviderDimension.h b/src/Mod/TechDraw/Gui/ViewProviderDimension.h index 0e6607b71c..9daf9c6b43 100644 --- a/src/Mod/TechDraw/Gui/ViewProviderDimension.h +++ b/src/Mod/TechDraw/Gui/ViewProviderDimension.h @@ -49,7 +49,8 @@ public: App::PropertyFloat LineWidth; App::PropertyColor Color; App::PropertyBool FlipArrowheads; - + App::PropertyBool TiltText; + App::PropertyBool ExtendToCenter; virtual void attach(App::DocumentObject *); virtual void setDisplayMode(const char* ModeName);