1
/***************************************************************************
2
* Copyright (c) 2013 Luke Parry <l.parry@warwick.ac.uk> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
26
# define _USE_MATH_DEFINES //resolves Windows & M_PI issues
32
# include <QGraphicsScene>
33
# include <QGraphicsSceneMouseEvent>
34
# include <QPaintDevice>
36
# include <QPainterPath>
37
# include <QSvgGenerator>
40
#include <App/Application.h>
41
#include <Base/Console.h>
42
#include <Base/Parameter.h>
43
#include <Base/UnitsApi.h>
44
#include <Gui/Command.h>
45
#include <Mod/TechDraw/App/DrawUtil.h>
46
#include <Mod/TechDraw/App/DrawViewDimension.h>
47
#include <Mod/TechDraw/App/DrawViewPart.h>
48
#include <Mod/TechDraw/App/Geometry.h>
50
#include "QGIViewDimension.h"
51
#include "PreferencesGui.h"
53
#include "QGIDimLines.h"
55
#include "QGCustomSvg.h"
56
#include "ViewProviderDimension.h"
65
//TODO: hide the Qt coord system (+y down).
67
using namespace TechDraw;
68
using namespace TechDrawGui;
85
QGIDatumLabel::QGIDatumLabel() : m_dragState(NoDrag)
93
setCacheMode(QGraphicsItem::NoCache);
94
setFlag(ItemSendsGeometryChanges, true);
95
setFlag(ItemIsMovable, true);
96
setFlag(ItemIsSelectable, true);
97
setAcceptHoverEvents(true);
98
setFiltersChildEvents(true);
100
m_dimText = new QGCustomText();
101
m_dimText->setTightBounding(true);
102
m_dimText->setParentItem(this);
103
m_tolTextOver = new QGCustomText();
104
m_tolTextOver->setTightBounding(true);
105
m_tolTextOver->setParentItem(this);
106
m_tolTextUnder = new QGCustomText();
107
m_tolTextUnder->setTightBounding(true);
108
m_tolTextUnder->setParentItem(this);
109
m_unitText = new QGCustomText();
110
m_unitText->setTightBounding(true);
111
m_unitText->setParentItem(this);
116
m_lineWidth = Rez::guiX(0.5);
119
QVariant QGIDatumLabel::itemChange(GraphicsItemChange change, const QVariant& value)
121
if (change == ItemSelectedHasChanged && scene()) {
127
if (m_dragState == Dragging) {
128
//stop the drag if we are no longer selected.
129
m_dragState = NoDrag;
130
Q_EMIT dragFinished();
134
else if (change == ItemPositionHasChanged && scene()) {
136
m_dragState = Dragging;
137
Q_EMIT dragging(m_ctrl);
140
return QGraphicsItem::itemChange(change, value);
143
void QGIDatumLabel::mousePressEvent(QGraphicsSceneMouseEvent* event)
145
if (event->modifiers() & Qt::ControlModifier) {
149
QGraphicsItem::mousePressEvent(event);
152
void QGIDatumLabel::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
154
// Base::Console().Message("QGIDL::mouseReleaseEvent()\n");
156
if (m_dragState == Dragging) {
157
m_dragState = NoDrag;
158
Q_EMIT dragFinished();
161
QGraphicsItem::mouseReleaseEvent(event);
164
void QGIDatumLabel::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
166
QGIViewDimension* qgivDimension = dynamic_cast<QGIViewDimension*>(parentItem());
167
if (!qgivDimension) {
168
qWarning() << "QGIDatumLabel::mouseDoubleClickEvent: No parent item";
172
auto ViewProvider = dynamic_cast<ViewProviderDimension*>(
173
qgivDimension->getViewProvider(qgivDimension->getViewObject()));
175
qWarning() << "QGIDatumLabel::mouseDoubleClickEvent: No valid view provider";
179
ViewProvider->startDefaultEditMode();
180
QGraphicsItem::mouseDoubleClickEvent(event);
183
void QGIDatumLabel::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
192
QGraphicsItem::hoverEnterEvent(event);
195
void QGIDatumLabel::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
205
QGraphicsItem::hoverLeaveEvent(event);
208
QRectF QGIDatumLabel::boundingRect() const
210
QRectF result = childrenBoundingRect();
211
result.adjust(-m_lineWidth * 4.0, 0.0, 0.0, 0.0);
215
void QGIDatumLabel::paint(QPainter* painter, const QStyleOptionGraphicsItem* option,
220
QStyleOptionGraphicsItem myOption(*option);
221
myOption.state &= ~QStyle::State_Selected;
223
// painter->setPen(Qt::blue);
224
// painter->drawRect(boundingRect()); //good for debugging
227
QPen prevPen = painter->pen();
228
QPen framePen(prevPen);
230
framePen.setWidthF(m_lineWidth);
231
framePen.setColor(m_dimText->defaultTextColor());
233
painter->setPen(framePen);
234
painter->drawRect(boundingRect());
235
painter->setPen(prevPen);
239
void QGIDatumLabel::setPosFromCenter(const double& xCenter, const double& yCenter)
241
prepareGeometryChange();
242
QGIViewDimension* qgivd = dynamic_cast<QGIViewDimension*>(parentItem());
246
const auto dim(dynamic_cast<TechDraw::DrawViewDimension*>(qgivd->getViewObject()));
251
//set label's Qt position(top, left) given boundingRect center point
252
setPos(xCenter - m_dimText->boundingRect().width() / 2.,
253
yCenter - m_dimText->boundingRect().height() / 2.);
255
QString uText = m_unitText->toPlainText();
256
if ((uText.size() > 0) && (uText.at(0) != QChar::fromLatin1(' '))) {
257
QString vText = m_dimText->toPlainText();
258
vText = vText + uText;
259
m_dimText->setPlainText(vText);
260
m_unitText->setPlainText(QString());
263
QRectF labelBox = m_dimText->boundingRect();
264
double right = labelBox.right();
265
double top = labelBox.top();
266
double bottom = labelBox.bottom();
267
double middle = (top + bottom) / 2.0;
270
QRectF unitBox = m_unitText->boundingRect();
271
double unitWidth = unitBox.width();
272
double unitRight = right + unitWidth;
273
// Set the m_unitText font *baseline* at same height as the m_dimText font baseline
274
m_unitText->setPos(right, 0.0);
276
//set tolerance position
277
QRectF overBox = m_tolTextOver->boundingRect();
278
double tolLeft = unitRight;
280
// Adjust for difference in tight and original bounding box sizes, note the y-coord down system
281
QPointF tol_adj = m_tolTextOver->tightBoundingAdjust();
282
m_tolTextOver->justifyLeftAt(tolLeft + tol_adj.x(), middle - tol_adj.y(), false);
283
tol_adj = m_tolTextUnder->tightBoundingAdjust();
284
m_tolTextUnder->justifyLeftAt(tolLeft + tol_adj.x(), middle + overBox.height() - tol_adj.y(),
288
void QGIDatumLabel::setLabelCenter()
290
//save label's bRect center (posX, posY) given Qt position (top, left)
291
posX = x() + m_dimText->boundingRect().width() / 2.;
292
posY = y() + m_dimText->boundingRect().height() / 2.;
295
void QGIDatumLabel::setFont(QFont font)
297
prepareGeometryChange();
298
m_dimText->setFont(font);
299
m_unitText->setFont(font);
301
double fontSize = font.pixelSize();
302
double tolAdj = getTolAdjust();
303
tFont.setPixelSize((int)(fontSize * tolAdj));
304
m_tolTextOver->setFont(tFont);
305
m_tolTextUnder->setFont(tFont);
308
void QGIDatumLabel::setDimString(QString text)
310
prepareGeometryChange();
311
m_dimText->setPlainText(text);
314
void QGIDatumLabel::setDimString(QString text, qreal maxWidth)
316
prepareGeometryChange();
317
m_dimText->setPlainText(text);
318
m_dimText->setTextWidth(maxWidth);
321
void QGIDatumLabel::setToleranceString()
323
prepareGeometryChange();
324
QGIViewDimension* qgivd = dynamic_cast<QGIViewDimension*>(parentItem());
328
const auto dim(dynamic_cast<TechDraw::DrawViewDimension*>(qgivd->getViewObject()));
331
// don't show if both are zero or if EqualTolerance is true
333
else if (!dim->hasOverUnderTolerance() || dim->EqualTolerance.getValue()
334
|| dim->TheoreticalExact.getValue()) {
335
m_tolTextOver->hide();
336
m_tolTextUnder->hide();
337
// we must explicitly empty the text otherwise the frame drawn for
338
// TheoreticalExact would be as wide as necessary for the text
339
m_tolTextOver->setPlainText(QString());
340
m_tolTextUnder->setPlainText(QString());
344
std::pair<std::string, std::string> labelTexts, unitTexts;
346
if (dim->ArbitraryTolerances.getValue()) {
347
labelTexts = dim->getFormattedToleranceValues(1);//copy tolerance spec
348
unitTexts.first = "";
349
unitTexts.second = "";
352
if (dim->isMultiValueSchema()) {
353
labelTexts = dim->getFormattedToleranceValues(0);//don't format multis
354
unitTexts.first = "";
355
unitTexts.second = "";
358
labelTexts = dim->getFormattedToleranceValues(1);// prefix value [unit] postfix
359
unitTexts = dim->getFormattedToleranceValues(2); //just the unit
363
if (labelTexts.first.empty()) {
364
m_tolTextUnder->hide();
367
m_tolTextUnder->setPlainText(QString::fromUtf8(labelTexts.first.c_str()));
368
m_tolTextUnder->show();
370
if (labelTexts.second.empty()) {
371
m_tolTextOver->hide();
374
m_tolTextOver->setPlainText(QString::fromUtf8(labelTexts.second.c_str()));
375
m_tolTextOver->show();
381
void QGIDatumLabel::setUnitString(QString text)
383
prepareGeometryChange();
384
if (text.isEmpty()) {
388
m_unitText->setPlainText(text);
394
int QGIDatumLabel::getPrecision()
396
if (Preferences::useGlobalDecimals()) {
397
return Base::UnitsApi::getDecimals();
399
return Preferences::getPreferenceGroup("Dimensions")->GetInt("AltDecimals", 2);
402
double QGIDatumLabel::getTolAdjust()
404
return Preferences::getPreferenceGroup("Dimensions")->GetFloat("TolSizeAdjust", 0.50);
408
void QGIDatumLabel::setPrettySel()
410
// Base::Console().Message("QGIDL::setPrettySel()\n");
411
m_dimText->setPrettySel();
412
m_tolTextOver->setPrettySel();
413
m_tolTextUnder->setPrettySel();
414
m_unitText->setPrettySel();
415
Q_EMIT setPretty(SEL);
418
void QGIDatumLabel::setPrettyPre()
420
// Base::Console().Message("QGIDL::setPrettyPre()\n");
421
m_dimText->setPrettyPre();
422
m_tolTextOver->setPrettyPre();
423
m_tolTextUnder->setPrettyPre();
424
m_unitText->setPrettyPre();
425
Q_EMIT setPretty(PRE);
428
void QGIDatumLabel::setPrettyNormal()
430
// Base::Console().Message("QGIDL::setPrettyNormal()\n");
431
m_dimText->setPrettyNormal();
432
m_tolTextOver->setPrettyNormal();
433
m_tolTextUnder->setPrettyNormal();
434
m_unitText->setPrettyNormal();
435
Q_EMIT setPretty(NORMAL);
438
void QGIDatumLabel::setColor(QColor color)
440
// Base::Console().Message("QGIDL::setColor(%s)\n", qPrintable(c.name()));
442
m_dimText->setColor(m_colNormal);
443
m_tolTextOver->setColor(m_colNormal);
444
m_tolTextUnder->setColor(m_colNormal);
445
m_unitText->setColor(m_colNormal);
448
//**************************************************************
449
QGIViewDimension::QGIViewDimension() : dvDimension(nullptr), hasHover(false), m_lineWidth(0.0)
451
setHandlesChildEvents(false);
452
setFlag(QGraphicsItem::ItemIsMovable, false);
453
setFlag(QGraphicsItem::ItemIsSelectable, false);
454
setAcceptHoverEvents(false);
455
setCacheMode(QGraphicsItem::NoCache);
457
datumLabel = new QGIDatumLabel();
458
datumLabel->setQDim(this);
460
addToGroup(datumLabel);
462
dimLines = new QGIDimLines();
463
addToGroup(dimLines);
465
aHead1 = new QGIArrow();
468
aHead2 = new QGIArrow();
471
datumLabel->setZValue(ZVALUE::DIMENSION);
472
aHead1->setZValue(ZVALUE::DIMENSION);
473
aHead2->setZValue(ZVALUE::DIMENSION);
474
dimLines->setZValue(ZVALUE::DIMENSION);
475
dimLines->setStyle(Qt::SolidLine);
477
// connecting the needed slots and signals
478
QObject::connect(datumLabel, &QGIDatumLabel::dragging, this, &QGIViewDimension::datumLabelDragged);
480
QObject::connect(datumLabel, &QGIDatumLabel::dragFinished, this, &QGIViewDimension::datumLabelDragFinished);
482
QObject::connect(datumLabel, &QGIDatumLabel::selected, this, &QGIViewDimension::select);
484
QObject::connect(datumLabel, &QGIDatumLabel::hover, this, &QGIViewDimension::hover);
486
QObject::connect(datumLabel, &QGIDatumLabel::setPretty, this, &QGIViewDimension::onPrettyChanged);
488
setZValue(ZVALUE::DIMENSION);//note: this won't paint dimensions over another View if it stacks
489
//above this Dimension's parent view. need Layers?
492
m_refFlag = new QGCustomSvg();
493
m_refFlag->setParentItem(this);
494
m_refFlag->load(QString::fromUtf8(":/icons/TechDraw_RefError.svg"));
495
m_refFlag->setZValue(ZVALUE::LOCK);
499
QVariant QGIViewDimension::itemChange(GraphicsItemChange change, const QVariant& value)
501
if (change == ItemSelectedHasChanged && scene()) {
503
datumLabel->setSelected(true);
506
datumLabel->setSelected(false);
511
if(change == ItemPositionChange && scene()) {
512
// QGIVDimension doesn't really change position the way other views do.
513
// If we call QGIView::itemChange it will set the position to (0,0) instead of
514
// using the label's position, and the Dimension will be in the wrong place.
515
// QGIVBalloon behaves the same way.
516
return QGraphicsItem::itemChange(change, value);
518
return QGIView::itemChange(change, value);
521
bool QGIViewDimension::getGroupSelection()
523
return datumLabel->isSelected();
526
//Set selection state for this and its children
527
void QGIViewDimension::setGroupSelection(bool isSelected)
529
// Base::Console().Message("QGIVD::setGroupSelection(%d)\n", b);
530
setSelected(isSelected);
531
datumLabel->setSelected(isSelected);
532
dimLines->setSelected(isSelected);
533
aHead1->setSelected(isSelected);
534
aHead2->setSelected(isSelected);
537
void QGIViewDimension::select(bool state)
543
//surrogate for hover enter (true), hover leave (false) events
544
void QGIViewDimension::hover(bool state)
550
void QGIViewDimension::setViewPartFeature(TechDraw::DrawViewDimension* obj)
552
// Base::Console().Message("QGIVD::setViewPartFeature()\n");
557
setViewFeature(static_cast<TechDraw::DrawView*>(obj));
560
// Set the QGIGroup Properties based on the DrawView
561
float x = Rez::guiX(obj->X.getValue());
562
float y = Rez::guiX(-obj->Y.getValue());
564
datumLabel->setPosFromCenter(x, y);
573
void QGIViewDimension::setNormalColorAll()
575
QColor qc = prefNormalColor();
576
datumLabel->setColor(qc);
577
dimLines->setNormalColor(qc);
578
aHead1->setNormalColor(qc);
579
aHead1->setFillColor(qc);
580
aHead2->setNormalColor(qc);
581
aHead2->setFillColor(qc);
584
//QGIViewDimension does not behave the same as other QGIView derived classes
585
//and so mouse events need to be ignored. Only the QGIDatumLabel mouse events are relevant.
586
void QGIViewDimension::mousePressEvent(QGraphicsSceneMouseEvent* event)
588
// Base::Console().Message("QGIVD::mousePressEvent() - %s\n", getViewName());
589
QGraphicsItem::mousePressEvent(event);
592
void QGIViewDimension::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
594
QGraphicsItem::mouseMoveEvent(event);
597
void QGIViewDimension::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
599
// Base::Console().Message("QGIVDim::mouseReleaseEvent() - %s\n", getViewName());
600
QGraphicsItem::mouseReleaseEvent(event);
603
void QGIViewDimension::updateView(bool update)
606
auto dim(dynamic_cast<TechDraw::DrawViewDimension*>(getViewObject()));
611
auto vp = static_cast<ViewProviderDimension*>(getViewProvider(getViewObject()));
616
if (update || dim->X.isTouched() || dim->Y.isTouched()) {
617
float x = Rez::guiX(dim->X.getValue());
618
float y = Rez::guiX(dim->Y.getValue());
619
datumLabel->setPosFromCenter(x, -y);
622
else if (vp->Fontsize.isTouched() || vp->Font.isTouched()) {
625
else if (vp->LineWidth.isTouched()) {
626
m_lineWidth = vp->LineWidth.getValue();
633
if (dim->hasGoodReferences()) {
636
m_refFlag->centerAt(datumLabel->pos() + datumLabel->boundingRect().center());
643
void QGIViewDimension::updateDim()
645
const auto dim(dynamic_cast<TechDraw::DrawViewDimension*>(getViewObject()));
649
auto vp = static_cast<ViewProviderDimension*>(getViewProvider(getViewObject()));
655
QString::fromUtf8(dim->getFormattedDimensionValue(1).c_str());// pre value [unit] post
656
if (dim->isMultiValueSchema()) {
658
QString::fromUtf8(dim->getFormattedDimensionValue(0).c_str());//don't format multis
661
QFont font = datumLabel->getFont();
662
font.setFamily(QString::fromUtf8(vp->Font.getValue()));
663
int fontSize = QGIView::exactFontSize(vp->Font.getValue(), vp->Fontsize.getValue());
664
font.setPixelSize(fontSize);
665
datumLabel->setFont(font);
667
prepareGeometryChange();
668
datumLabel->setDimString(labelText);
669
datumLabel->setToleranceString();
670
datumLabel->setPosFromCenter(datumLabel->X(), datumLabel->Y());
672
datumLabel->setFramed(dim->TheoreticalExact.getValue());
673
datumLabel->setLineWidth(m_lineWidth);
676
void QGIViewDimension::datumLabelDragged(bool ctrl)
682
void QGIViewDimension::datumLabelDragFinished()
684
auto dim(dynamic_cast<TechDraw::DrawViewDimension*>(getViewObject()));
690
double x = Rez::appX(datumLabel->X()), y = Rez::appX(datumLabel->Y());
691
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Drag Dimension"));
692
Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.X = %f",
693
dim->getNameInDocument(), x);
694
Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.Y = %f",
695
dim->getNameInDocument(), -y);
696
Gui::Command::commitCommand();
699
//this is for formatting and finding centers, not display
700
QString QGIViewDimension::getLabelText()
702
QString first = datumLabel->getDimText()->toPlainText();
703
QString second = datumLabel->getTolTextOver()->toPlainText();
704
QString third = datumLabel->getTolTextUnder()->toPlainText();
705
if (second.length() > third.length()) {
706
return first + second;
709
return first + third;
713
void QGIViewDimension::draw()
715
prepareGeometryChange();
720
TechDraw::DrawViewDimension* dim = dynamic_cast<TechDraw::DrawViewDimension*>(getViewObject());
721
if (!dim ||//nothing to draw, don't try
722
!dim->isDerivedFrom(TechDraw::DrawViewDimension::getClassTypeId())
723
|| !dim->has2DReferences()) {
729
const TechDraw::DrawViewPart* refObj = dim->getViewPart();
733
if (!refObj->hasGeometry()) {//nothing to draw yet (restoring)
739
auto vp = static_cast<ViewProviderDimension*>(getViewProvider(getViewObject()));
746
m_lineWidth = Rez::guiX(vp->LineWidth.getValue());
747
datumLabel->setRotation(0.0);
753
if (vp->RenderingExtent.getValue() > ViewProviderDimension::REND_EXTENT_NONE) {
754
// We are expected to draw something, not just display the value
755
const char* dimType = dim->Type.getValueAsString();
757
if (strcmp(dimType, "Distance") == 0 || strcmp(dimType, "DistanceX") == 0
758
|| strcmp(dimType, "DistanceY") == 0) {
759
drawDistance(dim, vp);
761
else if (strcmp(dimType, "Diameter") == 0) {
762
drawDiameter(dim, vp);
764
else if (strcmp(dimType, "Radius") == 0) {
767
else if (strcmp(dimType, "Angle") == 0 || strcmp(dimType, "Angle3Pt") == 0) {
771
Base::Console().Error("QGIVD::draw - this DimensionType is unknown: %s\n", dimType);
775
// No dimension lines are drawn, the arrows are hidden
776
dimLines->setPath(QPainterPath());
777
drawArrows(0, nullptr, nullptr, false);
781
if (hasHover && !datumLabel->isSelected()) {
784
else if (datumLabel->isSelected()) {
793
//TODO: parent redraw still required with new frame/label??
794
parentItem()->update();
798
double QGIViewDimension::getAnglePlacementFactor(double testAngle, double endAngle,
799
double startRotation)
801
if (startRotation > 0.0) {
802
startRotation = -startRotation;
803
endAngle -= startRotation;
804
if (endAngle > M_PI) {
809
if (testAngle > endAngle) {
813
if (testAngle >= endAngle + startRotation) {
818
if (testAngle > endAngle) {
822
if (testAngle >= endAngle + startRotation) {
829
int QGIViewDimension::compareAngleStraightness(double straightAngle, double leftAngle,
830
double rightAngle, double leftStrikeFactor,
831
double rightStrikeFactor)
833
double leftDelta = DrawUtil::angleComposition(M_PI, straightAngle - leftAngle);
834
double rightDelta = DrawUtil::angleComposition(rightAngle, -straightAngle);
836
if (fabs(leftDelta - rightDelta) <= Precision::Confusion()) {
840
if (leftStrikeFactor == rightStrikeFactor) {
841
double leftBend = fabs(leftDelta);
842
double rightBend = fabs(rightDelta);
844
return DrawUtil::sgn(leftBend - rightBend);
847
return rightStrikeFactor > leftStrikeFactor ? -1 : +1;
850
double QGIViewDimension::getIsoStandardLinePlacement(double labelAngle)
852
// According to ISO 129-1 Standard Figure 23, the bordering angle is 1/2 PI, resp. -1/2 PI
853
return labelAngle < -M_PI / 2.0 || labelAngle > +M_PI / 2.0 ? +1.0 : -1.0;
856
Base::Vector2d QGIViewDimension::getIsoRefOutsetPoint(const Base::BoundBox2d& labelRectangle,
859
return Base::Vector2d(right ? labelRectangle.MinX - getDefaultIsoReferenceLineOverhang()
860
: labelRectangle.MaxX + getDefaultIsoReferenceLineOverhang(),
861
labelRectangle.MinY - getIsoDimensionLineSpacing());
864
Base::Vector2d QGIViewDimension::getIsoRefJointPoint(const Base::BoundBox2d& labelRectangle,
867
return getIsoRefOutsetPoint(labelRectangle, !right);
870
Base::Vector2d QGIViewDimension::getAsmeRefOutsetPoint(const Base::BoundBox2d& labelRectangle,
873
return Base::Vector2d(right ? labelRectangle.MaxX : labelRectangle.MinX,
874
labelRectangle.GetCenter().y);
877
Base::Vector2d QGIViewDimension::getAsmeRefJointPoint(const Base::BoundBox2d& labelRectangle,
880
return Base::Vector2d(right ? labelRectangle.MaxX + getDefaultAsmeHorizontalLeaderLength()
881
: labelRectangle.MinX - getDefaultAsmeHorizontalLeaderLength(),
882
labelRectangle.GetCenter().y);
885
//find intersection of line L (through linePoint at angle lineAngle) and a line perpendicular to L
886
//passing through perpendicularPoint
887
//tricky vector algebra note:
888
//a*b is the magnitude of the projection of a onto b
889
//so we project a vector linePoint-perpendicularPoint onto unit vector in lineAngle direction giving
890
//the distance from linePoint to intersection, then make a displacement vector and add it to linePoint
891
Base::Vector2d QGIViewDimension::computePerpendicularIntersection(
892
const Base::Vector2d& linePoint, const Base::Vector2d& perpendicularPoint, double lineAngle)
895
+ Base::Vector2d::FromPolar((perpendicularPoint - linePoint)
896
* Base::Vector2d::FromPolar(1.0, lineAngle),
900
//calculate the end points of 1 extension line
901
//originPoint - a point on the distance line (end point)
902
//linePoint - point on dimension line that is perpendicular projection of distance line point
903
// onto dimension line
904
//1 extension line end point is the return value
905
//1 extension line end point is modified parameter startPoint
906
Base::Vector2d QGIViewDimension::computeExtensionLinePoints(const Base::Vector2d& originPoint,
907
const Base::Vector2d& linePoint,
908
double hintAngle, double overhangSize,
910
Base::Vector2d& startPoint)
912
Base::Vector2d direction(linePoint - originPoint);
913
double rawLength = direction.Length();
915
if (rawLength <= Precision::Confusion()) {
916
direction = Base::Vector2d::FromPolar(1.0, hintAngle);
919
direction = direction / rawLength;
922
if (overhangSize > rawLength - gapSize) {
923
// The extension line would be smaller than extension line overhang, keep it at least so long
924
startPoint = linePoint - overhangSize * direction;
927
startPoint = linePoint - (rawLength - gapSize) * direction;
930
return linePoint + overhangSize * direction;
933
double QGIViewDimension::computeLineAndLabelAngles(const Base::Vector2d& rotationCenter,
934
const Base::Vector2d& labelCenter,
935
double lineLabelDistance, double& lineAngle,
938
// By default horizontal line and no label rotation
942
Base::Vector2d rawDirection(labelCenter - rotationCenter);
943
double rawDistance = rawDirection.Length();
944
if (rawDistance <= Precision::Confusion()) {// Almost single point, can't tell
948
double rawAngle = rawDirection.Angle();
949
lineAngle = rawAngle;
951
// If we are too close to the line origin, no further adjustments
952
if (lineLabelDistance >= rawDistance) {
956
// Rotate the line by angle between the label rectangle center and label bottom side center
957
double devAngle = getIsoStandardLinePlacement(rawAngle) * asin(lineLabelDistance / rawDistance);
958
lineAngle = DrawUtil::angleComposition(lineAngle, devAngle);
960
labelAngle = devAngle < 0.0 ? lineAngle : DrawUtil::angleComposition(lineAngle, M_PI);
966
QGIViewDimension::computeLineStrikeFactor(const Base::BoundBox2d& labelRectangle,
967
const Base::Vector2d& lineOrigin, double lineAngle,
968
const std::vector<std::pair<double, bool>>& drawMarking)
970
if (drawMarking.size() < 2) {
974
std::vector<Base::Vector2d> intersectionPoints;
975
unsigned int startIndex = 0;
976
unsigned int currentIndex = 1;
978
while (currentIndex < drawMarking.size()) {
979
if (drawMarking[currentIndex].second != drawMarking[startIndex].second) {
980
if (drawMarking[startIndex].second) {
981
double segmentBase = drawMarking[startIndex].first;
982
double segmentLength = drawMarking[currentIndex].first - segmentBase;
984
DrawUtil::findLineSegmentRectangleIntersections(lineOrigin, lineAngle, segmentBase,
985
segmentLength, labelRectangle,
989
startIndex = currentIndex;
995
return intersectionPoints.size() >= 2 ? 1.0 : 0.0;
999
QGIViewDimension::computeArcStrikeFactor(const Base::BoundBox2d& labelRectangle,
1000
const Base::Vector2d& arcCenter, double arcRadius,
1001
const std::vector<std::pair<double, bool>>& drawMarking)
1003
if (drawMarking.empty()) {
1007
unsigned int entryIndex = 0;
1008
while (entryIndex < drawMarking.size() && drawMarking[entryIndex].second) {
1012
std::vector<Base::Vector2d> intersectionPoints;
1014
if (entryIndex >= drawMarking.size()) {
1015
DrawUtil::findCircleRectangleIntersections(arcCenter, arcRadius, labelRectangle,
1016
intersectionPoints);
1019
unsigned int startIndex = entryIndex;
1020
unsigned int currentIndex = entryIndex;
1023
currentIndex %= drawMarking.size();
1025
if (drawMarking[currentIndex].second != drawMarking[startIndex].second) {
1026
if (drawMarking[startIndex].second) {
1027
double arcAngle = drawMarking[startIndex].first;
1028
double arcRotation = drawMarking[currentIndex].first - arcAngle;
1029
if (arcRotation < 0.0) {
1030
arcRotation += M_2PI;
1033
DrawUtil::findCircularArcRectangleIntersections(arcCenter, arcRadius, arcAngle,
1034
arcRotation, labelRectangle,
1035
intersectionPoints);
1038
startIndex = currentIndex;
1040
} while (currentIndex != entryIndex);
1043
return intersectionPoints.size() >= 2 ? 1.0 : 0.0;
1046
double QGIViewDimension::normalizeStartPosition(double& startPosition, double& lineAngle)
1048
if (startPosition > 0.0) {
1049
startPosition = -startPosition;
1057
double QGIViewDimension::normalizeStartRotation(double& startRotation)
1059
if (copysign(1.0, startRotation) > 0.0) {
1060
startRotation = -startRotation;
1067
bool QGIViewDimension::constructDimensionLine(
1068
const Base::Vector2d& targetPoint, double lineAngle, double startPosition, double jointPosition,
1069
const Base::BoundBox2d& labelRectangle, int arrowCount, int standardStyle, bool flipArrows,
1070
std::vector<std::pair<double, bool>>& outputMarking) const
1072
// The start position > 0 is not expected, the caller must handle this
1073
if (startPosition > 0.0) {
1074
Base::Console().Error(
1075
"QGIVD::constructDimLine - Start Position must not be positive! Received: %f\n",
1080
double labelBorder = 0.0;
1081
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) {
1082
labelBorder = labelRectangle.Width() * 0.5 + getDefaultIsoReferenceLineOverhang();
1084
else if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
1085
std::vector<Base::Vector2d> intersectionPoints;
1086
DrawUtil::findLineRectangleIntersections(targetPoint, lineAngle, labelRectangle,
1087
intersectionPoints);
1089
if (intersectionPoints.size() >= 2) {
1090
labelBorder = (intersectionPoints[0] - labelRectangle.GetCenter()).Length();
1094
bool autoFlipArrows = false;
1095
if (jointPosition + labelBorder > 0.0) {
1096
// If label sticks out, extend the dimension line beyond the end point (0.0)
1097
DrawUtil::intervalMarkLinear(outputMarking, 0.0, jointPosition + labelBorder, true);
1098
autoFlipArrows = true;
1101
if (jointPosition - labelBorder < startPosition) {
1102
DrawUtil::intervalMarkLinear(outputMarking, startPosition,
1103
jointPosition - labelBorder - startPosition, true);
1105
// For only one arrow and zero width line skip flipping, it already points correctly
1106
if (arrowCount > 1 || startPosition < 0.0) {
1107
autoFlipArrows = true;
1111
flipArrows ^= autoFlipArrows;
1113
|| (standardStyle != ViewProviderDimension::STD_STYLE_ASME_INLINED
1114
&& standardStyle != ViewProviderDimension::STD_STYLE_ASME_REFERENCING)) {
1115
// If arrows point outside, or ASME standard is not followed,
1116
// add the line part between start and end
1117
DrawUtil::intervalMarkLinear(outputMarking, 0.0, startPosition, true);
1120
// For ASME Inlined, cut out the part of line occupied by the value
1121
if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
1122
DrawUtil::intervalMarkLinear(outputMarking, jointPosition - labelBorder, labelBorder * 2.0,
1126
// Add the arrow tails - these are drawn always
1127
double placementFactor = flipArrows ? +1.0 : -1.0;
1128
DrawUtil::intervalMarkLinear(outputMarking, 0.0, placementFactor * getDefaultArrowTailLength(),
1130
if (arrowCount > 1) {
1131
DrawUtil::intervalMarkLinear(outputMarking, startPosition,
1132
-placementFactor * getDefaultArrowTailLength(), true);
1138
bool QGIViewDimension::constructDimensionArc(
1139
const Base::Vector2d& arcCenter, double arcRadius, double endAngle, double startRotation,
1140
double handednessFactor, double jointRotation, const Base::BoundBox2d& labelRectangle,
1141
int arrowCount, int standardStyle, bool flipArrows,
1142
std::vector<std::pair<double, bool>>& outputMarking) const
1144
// The start rotation > 0 is not expected, the caller must handle this
1145
if (startRotation > 0.0) {
1146
Base::Console().Error(
1147
"QGIVD::constructDimArc - Start Rotation must not be positive! Received: %f\n",
1152
double startDelta = 0.0;
1153
double endDelta = 0.0;
1154
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) {
1155
double borderRadius = (labelRectangle.GetCenter() - arcCenter).Length();
1157
if (borderRadius > arcRadius) {
1158
borderRadius = arcRadius + getIsoDimensionLineSpacing();
1160
else if (borderRadius < arcRadius) {
1161
borderRadius = arcRadius - getIsoDimensionLineSpacing();
1164
// ISO oriented labels are symmetrical along their center axis
1165
startDelta = atan((labelRectangle.Width() * 0.5 + getDefaultIsoReferenceLineOverhang())
1167
endDelta = startDelta;
1169
else if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
1170
std::vector<Base::Vector2d> intersectionPoints;
1172
DrawUtil::findCircleRectangleIntersections(arcCenter, arcRadius, labelRectangle,
1173
intersectionPoints);
1175
// We do not want to handle other cases than 2 intersection points - if so, act as if there were none
1176
if (intersectionPoints.size() == 2) {
1177
double zeroAngle = (labelRectangle.GetCenter() - arcCenter).Angle();
1180
DrawUtil::angleDifference(zeroAngle, (intersectionPoints[0] - arcCenter).Angle());
1182
DrawUtil::angleDifference(zeroAngle, (intersectionPoints[1] - arcCenter).Angle());
1184
// End delta is the angle in the end point direction, start delta in the opposite
1185
// Keep orientation and the computation sign in sync
1186
if ((endDelta < 0.0) == (handednessFactor < 0.0)) {
1187
std::swap(startDelta, endDelta);
1190
startDelta = fabs(startDelta);
1191
endDelta = fabs(endDelta);
1195
bool autoFlipArrows = false;
1196
if (jointRotation + endDelta > 0.0) {
1197
// If label exceeds end angle ray, extend the dimension arc and flip arrows
1198
DrawUtil::intervalMarkCircular(outputMarking, endAngle,
1199
handednessFactor * (jointRotation + endDelta), true);
1200
autoFlipArrows = true;
1203
if (jointRotation - startDelta < startRotation) {
1204
DrawUtil::intervalMarkCircular(
1205
outputMarking, endAngle + handednessFactor * startRotation,
1206
handednessFactor * (jointRotation - startDelta - startRotation), true);
1208
// For only one arrow and zero width line skip flipping, it already points correctly
1209
if (arrowCount > 1 || startRotation < 0.0) {
1210
autoFlipArrows = true;
1214
flipArrows ^= autoFlipArrows;
1216
|| (standardStyle != ViewProviderDimension::STD_STYLE_ASME_INLINED
1217
&& standardStyle != ViewProviderDimension::STD_STYLE_ASME_REFERENCING)) {
1218
// If arrows point outside, or ASME standard is not followed,
1219
// add the arc part between start and end
1220
DrawUtil::intervalMarkCircular(outputMarking, endAngle, handednessFactor * startRotation,
1224
// For ASME Inlined, cut out the part of arc occupied by the value
1225
if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
1226
DrawUtil::intervalMarkCircular(outputMarking,
1227
endAngle + handednessFactor * (jointRotation - startDelta),
1228
handednessFactor * (startDelta + endDelta), false);
1231
// Add the arrow tails - these are drawn always
1233
arcRadius >= Precision::Confusion() ? getDefaultArrowTailLength() / arcRadius : M_PI_4;
1234
double placementFactor = flipArrows ? +1.0 : -1.0;
1236
DrawUtil::intervalMarkCircular(outputMarking, endAngle,
1237
placementFactor * handednessFactor * tailDelta, true);
1238
if (arrowCount > 1) {
1239
DrawUtil::intervalMarkCircular(outputMarking, endAngle + handednessFactor * startRotation,
1240
-placementFactor * handednessFactor * tailDelta, true);
1246
void QGIViewDimension::resetArrows() const
1248
aHead1->setDirMode(true);
1249
aHead1->setRotation(0.0);
1250
aHead1->setFlipped(false);
1252
aHead2->setDirMode(true);
1253
aHead2->setRotation(0.0);
1254
aHead2->setFlipped(false);
1257
void QGIViewDimension::drawArrows(int count, const Base::Vector2d positions[], double angles[],
1260
const int arrowCount = 2;
1261
QGIArrow* arrows[arrowCount] = {aHead1, aHead2};
1263
arrowPositionsToFeature(positions);
1265
for (int i = 0; i < arrowCount; ++i) {
1266
QGIArrow* arrow = arrows[i];
1268
if (positions && angles) {
1269
arrow->setPos(toQtGui(positions[i]));
1270
arrow->setDirection(toQtRad(angles[i]));
1278
arrow->setStyle(QGIArrow::getPrefArrowStyle());
1279
auto vp = static_cast<ViewProviderDimension*>(getViewProvider(getViewObject()));
1280
auto arrowSize = vp->Arrowsize.getValue();
1281
arrow->setSize(arrowSize);
1282
arrow->setFlipped(flipped);
1284
if (QGIArrow::getPrefArrowStyle() != 7) {// if not "None"
1294
void QGIViewDimension::arrowPositionsToFeature(const Base::Vector2d positions[]) const
1296
auto dim(dynamic_cast<TechDraw::DrawViewDimension*>(getViewObject()));
1301
dim->saveArrowPositions(positions);
1304
void QGIViewDimension::drawSingleLine(QPainterPath& painterPath, const Base::Vector2d& lineOrigin,
1305
double lineAngle, double startPosition,
1306
double endPosition) const
1308
if (endPosition == startPosition) {
1312
painterPath.moveTo(toQtGui(lineOrigin + Base::Vector2d::FromPolar(startPosition, lineAngle)));
1313
painterPath.lineTo(toQtGui(lineOrigin + Base::Vector2d::FromPolar(endPosition, lineAngle)));
1317
//adds line segments to painterPath from lineOrigin along lineAngle
1318
//segment length is determined by drawMarking entries
1319
void QGIViewDimension::drawMultiLine(QPainterPath& painterPath, const Base::Vector2d& lineOrigin,
1321
const std::vector<std::pair<double, bool>>& drawMarking) const
1323
if (drawMarking.size() < 2) {
1327
unsigned int startIndex = 0;
1328
unsigned int currentIndex = 1;
1329
while (currentIndex < drawMarking.size()) {
1330
if (drawMarking[currentIndex].second != drawMarking[startIndex].second) {
1331
if (drawMarking[startIndex].second) {
1332
drawSingleLine(painterPath, lineOrigin, lineAngle, drawMarking[startIndex].first,
1333
drawMarking[currentIndex].first);
1336
startIndex = currentIndex;
1343
void QGIViewDimension::drawSingleArc(QPainterPath& painterPath, const Base::Vector2d& arcCenter,
1344
double arcRadius, double startAngle, double endAngle) const
1346
if (endAngle == startAngle) {
1349
if (endAngle < startAngle) {
1353
QRectF qtArcRectangle(
1354
toQtGui(Base::BoundBox2d(arcCenter.x - arcRadius, arcCenter.y - arcRadius,
1355
arcCenter.x + arcRadius, arcCenter.y + arcRadius)));
1357
// In arc drawing are for some reason Qt's angles counterclockwise as in our computations...
1358
painterPath.arcMoveTo(qtArcRectangle, toDeg(startAngle));
1359
painterPath.arcTo(qtArcRectangle, toDeg(startAngle), toDeg(endAngle - startAngle));
1362
void QGIViewDimension::drawMultiArc(QPainterPath& painterPath, const Base::Vector2d& arcCenter,
1364
const std::vector<std::pair<double, bool>>& drawMarking) const
1366
if (drawMarking.empty()) {
1370
unsigned int entryIndex = 0;
1371
while (entryIndex < drawMarking.size() && drawMarking[entryIndex].second) {
1375
if (entryIndex >= drawMarking.size()) {
1376
drawSingleArc(painterPath, arcCenter, arcRadius, 0, M_2PI);
1380
unsigned int startIndex = entryIndex;
1381
unsigned int currentIndex = entryIndex;
1384
currentIndex %= drawMarking.size();
1386
if (drawMarking[currentIndex].second != drawMarking[startIndex].second) {
1387
if (drawMarking[startIndex].second) {
1388
drawSingleArc(painterPath, arcCenter, arcRadius, drawMarking[startIndex].first,
1389
drawMarking[currentIndex].first);
1392
startIndex = currentIndex;
1394
} while (currentIndex != entryIndex);
1398
//adds dimension line to painterPath
1399
//dimension line starts at targetPoint and continues for a distance (startPosition?) along lineAngle
1400
//jointPosition - distance of reference line from 1 extension line??
1401
//lineAngle - Clockwise angle of distance line with horizontal
1402
void QGIViewDimension::drawDimensionLine(QPainterPath& painterPath,
1403
const Base::Vector2d& targetPoint, double lineAngle,
1404
double startPosition, double jointPosition,
1405
const Base::BoundBox2d& labelRectangle, int arrowCount,
1406
int standardStyle, bool flipArrows) const
1408
// Keep the convention start position <= 0
1409
jointPosition *= normalizeStartPosition(startPosition, lineAngle);
1411
std::vector<std::pair<double, bool>> drawMarks;
1413
constructDimensionLine(targetPoint, lineAngle, startPosition, jointPosition, labelRectangle,
1414
arrowCount, standardStyle, flipArrows, drawMarks);
1416
drawMultiLine(painterPath, targetPoint, lineAngle, drawMarks);
1418
Base::Vector2d arrowPositions[2];
1419
arrowPositions[0] = targetPoint;
1420
arrowPositions[1] = targetPoint + Base::Vector2d::FromPolar(startPosition, lineAngle);
1422
double arrowAngles[2];
1423
arrowAngles[0] = lineAngle;
1424
arrowAngles[1] = lineAngle + M_PI;
1426
drawArrows(arrowCount, arrowPositions, arrowAngles, flipArrows);
1429
void QGIViewDimension::drawDimensionArc(QPainterPath& painterPath, const Base::Vector2d& arcCenter,
1430
double arcRadius, double endAngle, double startRotation,
1431
double jointAngle, const Base::BoundBox2d& labelRectangle,
1432
int arrowCount, int standardStyle, bool flipArrows) const
1434
// Keep the convention start rotation <= 0
1435
double handednessFactor = normalizeStartRotation(startRotation);
1437
// Split the rest of 2PI minus the angle and assign joint offset so > 0 is closer to end arc side
1438
double jointRotation = handednessFactor * (jointAngle - endAngle);
1439
if (fabs(jointRotation - startRotation * 0.5) > M_PI) {
1440
jointRotation += jointRotation < 0.0 ? +M_2PI : -M_2PI;
1443
std::vector<std::pair<double, bool>> drawMarks;
1444
flipArrows = constructDimensionArc(arcCenter, arcRadius, endAngle, startRotation,
1445
handednessFactor, jointRotation, labelRectangle, arrowCount,
1446
standardStyle, flipArrows, drawMarks);
1448
drawMultiArc(painterPath, arcCenter, arcRadius, drawMarks);
1450
Base::Vector2d arrowPositions[2];
1451
arrowPositions[0] = arcCenter + Base::Vector2d::FromPolar(arcRadius, endAngle);
1452
arrowPositions[1] = arcCenter
1453
+ Base::Vector2d::FromPolar(arcRadius, endAngle + handednessFactor * startRotation);
1455
double arrowAngles[2];
1456
arrowAngles[0] = endAngle + handednessFactor * M_PI_2;
1457
arrowAngles[1] = endAngle + handednessFactor * (startRotation - M_PI_2);
1459
drawArrows(arrowCount, arrowPositions, arrowAngles, flipArrows);
1462
//draw any of 3 distance dimension types
1463
//startPoint, endPoint - ends of actual distance line
1464
//lineAngle - angle of actual line with horizontal
1465
//target points - projection of reference line ends on to extension line
1466
//startCross & endCross - real intersection of extension lines and dimension line
1467
//dimension line - main annotation line
1468
//reference line - line under dimension text in referenced styles
1469
//joint points - ends of reference line
1470
void QGIViewDimension::drawDistanceExecutive(const Base::Vector2d& startPoint,
1471
const Base::Vector2d& endPoint, double lineAngle,
1472
const Base::BoundBox2d& labelRectangle,
1473
int standardStyle, int renderExtent,
1474
bool flipArrows) const
1476
QPainterPath distancePath;
1478
Base::Vector2d labelCenter(labelRectangle.GetCenter());
1479
double labelAngle = 0.0;
1481
//startCross and endCross are points where extension line intersects dimension line
1482
Base::Vector2d startCross;
1483
Base::Vector2d endCross;
1484
int arrowCount = renderExtent >= ViewProviderDimension::REND_EXTENT_NORMAL
1485
|| renderExtent == ViewProviderDimension::REND_EXTENT_CONFINED
1489
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
1490
|| standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING) {
1491
// The dimensional value text must stay horizontal in these styles
1493
//jointPoints are the ends of the reference line
1494
Base::Vector2d jointPoints[2];
1496
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING) {
1497
jointPoints[0] = getIsoRefJointPoint(labelRectangle, false);
1498
jointPoints[1] = getIsoRefJointPoint(labelRectangle, true);
1501
jointPoints[0] = getAsmeRefJointPoint(labelRectangle, false);
1502
jointPoints[1] = getAsmeRefJointPoint(labelRectangle, true);
1505
//targetPoints are the projection of reference line endpoints onto endPoint's extension line
1506
Base::Vector2d targetPoints[2];
1507
targetPoints[0] = computePerpendicularIntersection(jointPoints[0], endPoint, lineAngle);
1508
targetPoints[1] = computePerpendicularIntersection(jointPoints[1], endPoint, lineAngle);
1510
// Compute and normalize (i.e. make < 0) the start position
1511
Base::Vector2d lineDirection(Base::Vector2d::FromPolar(1.0, lineAngle));
1512
double startPosition =
1513
arrowCount > 1 ? lineDirection * (startPoint - targetPoints[0]) : 0.0;
1514
lineDirection *= normalizeStartPosition(startPosition, lineAngle);
1516
// Find the positions where the reference line attaches to the dimension line
1517
//jointPoints are the ends of the reference line
1518
//targetPoints - projection of reference line on to extension line
1519
//jointPositions - displacement of jointPoints from ext line
1520
double jointPositions[2];
1521
jointPositions[0] = lineDirection * (jointPoints[0] - targetPoints[0]);
1522
jointPositions[1] = lineDirection * (jointPoints[1] - targetPoints[1]);
1524
// Orient the leader line angle correctly towards the target point
1527
jointPositions[0] > 0.0 ? DrawUtil::angleComposition(lineAngle, M_PI) : lineAngle;
1529
jointPositions[1] > 0.0 ? DrawUtil::angleComposition(lineAngle, M_PI) : lineAngle;
1531
// Select the placement, where the label is not obscured by the leader line
1532
// or (if both behave the same) the one that bends the reference line less
1533
double strikeFactors[2];
1535
std::vector<std::pair<double, bool>> lineMarking;
1536
constructDimensionLine(targetPoints[0], lineAngle, startPosition, jointPositions[0],
1537
labelRectangle, arrowCount, standardStyle, flipArrows, lineMarking);
1539
computeLineStrikeFactor(labelRectangle, targetPoints[0], lineAngle, lineMarking);
1541
lineMarking.clear();
1542
constructDimensionLine(targetPoints[1], lineAngle, startPosition, jointPositions[1],
1543
labelRectangle, arrowCount, standardStyle, flipArrows, lineMarking);
1545
computeLineStrikeFactor(labelRectangle, targetPoints[1], lineAngle, lineMarking);
1548
compareAngleStraightness(0.0, angles[0], angles[1], strikeFactors[0], strikeFactors[1]);
1549
if (selected == 0) {
1550
// Select the side closer, so the label is on the outer side of the dimension line
1551
Base::Vector2d perpendicularDir(lineDirection.Perpendicular());
1552
if (fabs((jointPoints[0] - endPoint) * perpendicularDir)
1553
> fabs((jointPoints[1] - endPoint) * perpendicularDir)) {
1557
else if (selected < 0) {
1561
//find points where extension lines meet dimension line
1562
endCross = targetPoints[selected];
1563
startCross = targetPoints[selected] + Base::Vector2d::FromPolar(startPosition, lineAngle);
1565
drawDimensionLine(distancePath, endCross, lineAngle, startPosition,
1566
jointPositions[selected], labelRectangle, arrowCount, standardStyle,
1569
Base::Vector2d outsetPoint(
1570
standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
1571
? getIsoRefOutsetPoint(labelRectangle, selected == 1)// 0 = left, 1 = right
1572
: getAsmeRefOutsetPoint(labelRectangle, selected == 1));
1574
//add the reference line to the QPainterPath
1575
distancePath.moveTo(toQtGui(outsetPoint));
1576
distancePath.lineTo(toQtGui(jointPoints[selected]));
1579
else if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) {
1580
// We may rotate the label so no leader and reference lines are needed
1581
double placementFactor = getIsoStandardLinePlacement(lineAngle);
1583
placementFactor > 0.0 ? DrawUtil::angleComposition(lineAngle, M_PI) : lineAngle;
1585
// Find out the projection of label center on the line with given angle
1586
Base::Vector2d labelProjection(
1588
+ Base::Vector2d::FromPolar(
1590
* (labelRectangle.Height() * 0.5 + getIsoDimensionLineSpacing()),
1591
lineAngle + M_PI_2));
1593
// Compute the dimensional line start and end crossings with (virtual) extension lines
1594
//check for isometric direction and if iso compute non-perpendicular intersection of dim line and ext lines
1595
Base::Vector2d lineDirection(Base::Vector2d::FromPolar(1.0, lineAngle));
1596
startCross = computePerpendicularIntersection(labelProjection, startPoint, lineAngle);
1597
endCross = computePerpendicularIntersection(labelProjection, endPoint, lineAngle);
1599
// Find linear coefficients of crossings
1600
double startPosition = arrowCount > 1 ? lineDirection * (startCross - endCross) : 0.0;
1601
double labelPosition = lineDirection * (labelProjection - endCross);
1603
drawDimensionLine(distancePath, endCross, lineAngle, startPosition, labelPosition,
1604
labelRectangle, arrowCount, standardStyle, flipArrows);
1607
else if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
1608
// Text must remain horizontal, but it may split the leader line
1609
Base::Vector2d lineDirection(Base::Vector2d::FromPolar(1.0, lineAngle));
1610
startCross = computePerpendicularIntersection(labelCenter, startPoint, lineAngle);
1611
endCross = computePerpendicularIntersection(labelCenter, endPoint, lineAngle);
1613
// Find linear coefficients of crossings
1614
double startPosition = arrowCount > 1 ? lineDirection * (startCross - endCross) : 0.0;
1615
double labelPosition = lineDirection * (labelCenter - endCross);
1617
drawDimensionLine(distancePath, endCross, lineAngle, startPosition, labelPosition,
1618
labelRectangle, arrowCount, standardStyle, flipArrows);
1621
Base::Console().Error(
1622
"QGIVD::drawDistanceExecutive - this Standard&Style is not supported: %d\n",
1627
auto vp = static_cast<ViewProviderDimension*>(getViewProvider(getViewObject()));
1630
if (arrowCount > 0 && renderExtent >= ViewProviderDimension::REND_EXTENT_REDUCED) {
1631
double gapSize = 0.0;
1632
if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING
1633
|| standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
1634
double factor = vp->GapFactorASME.getValue();
1635
gapSize = Rez::appX(m_lineWidth * factor);
1637
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
1638
|| standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) {
1639
double factor = vp->GapFactorISO.getValue();
1640
gapSize = Rez::appX(m_lineWidth * factor);
1643
Base::Vector2d extensionOrigin;
1644
Base::Vector2d extensionTarget(computeExtensionLinePoints(
1645
endPoint, endCross, lineAngle + M_PI_2, getDefaultExtensionLineOverhang(), gapSize,
1647
//draw 1st extension line
1648
distancePath.moveTo(toQtGui(extensionOrigin));
1649
distancePath.lineTo(toQtGui(extensionTarget));
1651
if (arrowCount > 1) {
1652
extensionTarget = computeExtensionLinePoints(startPoint, startCross, lineAngle + M_PI_2,
1653
getDefaultExtensionLineOverhang(), gapSize,
1655
//draw second extension line
1656
distancePath.moveTo(toQtGui(extensionOrigin));
1657
distancePath.lineTo(toQtGui(extensionTarget));
1661
datumLabel->setTransformOriginPoint(datumLabel->boundingRect().center());
1662
datumLabel->setRotation(toQtDeg(labelAngle));
1664
dimLines->setPath(distancePath);
1667
//draw any of 3 distance dimension types with user override of dimension and extension line directions
1668
//startPoint, endPoint - ends of actual distance line
1669
//lineAngle - desired angle of dimension line with horizontal
1670
//extensionAngle - desired angle of extension lines with horizontal
1671
void QGIViewDimension::drawDistanceOverride(const Base::Vector2d& startPoint,
1672
const Base::Vector2d& endPoint, double lineAngle,
1673
const Base::BoundBox2d& labelRectangle,
1674
int standardStyle, int renderExtent, bool flipArrows,
1675
double extensionAngle) const
1677
QPainterPath distancePath;
1679
Base::Vector2d labelCenter(labelRectangle.GetCenter());
1680
double labelAngle = 0.0;
1682
//startCross and endCross are points where extension lines intersect dimension line
1683
Base::Vector2d startCross;
1684
Base::Vector2d endCross;
1685
Base::Vector2d lineDirection(Base::Vector2d::FromPolar(1.0, lineAngle));
1686
Base::Vector2d extensionDirection(Base::Vector2d::FromPolar(1.0, extensionAngle));
1688
int arrowCount = renderExtent >= ViewProviderDimension::REND_EXTENT_NORMAL
1689
|| renderExtent == ViewProviderDimension::REND_EXTENT_CONFINED
1693
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
1694
|| standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING) {
1695
// The dimensional value text must stay horizontal in these styles
1697
//refEndPoints are the ends of the reference line
1698
Base::Vector2d refEndPoints[2];
1700
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING) {
1701
refEndPoints[0] = getIsoRefJointPoint(labelRectangle, false);
1702
refEndPoints[1] = getIsoRefJointPoint(labelRectangle, true);
1705
refEndPoints[0] = getAsmeRefJointPoint(labelRectangle, false);
1706
refEndPoints[1] = getAsmeRefJointPoint(labelRectangle, true);
1709
//targetPoints are the projection of reference line endpoints onto endPoint's extension line
1710
Base::Vector2d targetPoints[2];
1712
DrawUtil::Intersect2d(refEndPoints[0], lineDirection, endPoint, extensionDirection);
1714
DrawUtil::Intersect2d(refEndPoints[1], lineDirection, endPoint, extensionDirection);
1715
Base::Vector2d pointOnStartExtension =
1716
DrawUtil::Intersect2d(endPoint, lineDirection, startPoint, extensionDirection);
1717
double startPosition =
1718
arrowCount > 1 ? lineDirection * (pointOnStartExtension - endPoint) : 0.0;
1720
// Compute and normalize (i.e. make < 0) the start position
1721
lineDirection *= normalizeStartPosition(startPosition, lineAngle);
1723
// Find the positions where the reference line attaches to the dimension line
1724
//refEndPoints are the ends of the reference line
1725
//targetPoints - projection of reference line on to extension line
1726
//jointPositions - displacement of refEndPoints from extension line
1727
double jointPositions[2];
1728
jointPositions[0] = lineDirection * (refEndPoints[0] - targetPoints[0]);
1729
jointPositions[1] = lineDirection * (refEndPoints[1] - targetPoints[1]);
1731
// Orient the leader line angle correctly towards the target point
1734
jointPositions[0] > 0.0 ? DrawUtil::angleComposition(lineAngle, M_PI) : lineAngle;
1736
jointPositions[1] > 0.0 ? DrawUtil::angleComposition(lineAngle, M_PI) : lineAngle;
1738
// Select the placement, where the label is not obscured by the leader line
1739
// or (if both behave the same) the one that bends the reference line less
1740
double strikeFactors[2];
1742
std::vector<std::pair<double, bool>> lineMarking;
1743
constructDimensionLine(targetPoints[0], lineAngle, startPosition, jointPositions[0],
1744
labelRectangle, arrowCount, standardStyle, flipArrows, lineMarking);
1746
computeLineStrikeFactor(labelRectangle, targetPoints[0], lineAngle, lineMarking);
1748
lineMarking.clear();
1749
constructDimensionLine(targetPoints[1], lineAngle, startPosition, jointPositions[1],
1750
labelRectangle, arrowCount, standardStyle, flipArrows, lineMarking);
1752
computeLineStrikeFactor(labelRectangle, targetPoints[1], lineAngle, lineMarking);
1755
compareAngleStraightness(0.0, angles[0], angles[1], strikeFactors[0], strikeFactors[1]);
1756
if (selected == 0) {
1757
// Select the side closer, so the label is on the outer side of the dimension line
1758
Base::Vector2d perpendicularDir(lineDirection.Perpendicular());
1759
if (fabs((refEndPoints[0] - endPoint) * perpendicularDir)
1760
> fabs((refEndPoints[1] - endPoint) * perpendicularDir)) {
1764
else if (selected < 0) {
1768
//find points where extension lines meet dimension line
1769
Base::Vector2d pointOnDimLine(refEndPoints[selected].x, refEndPoints[selected].y);
1771
DrawUtil::Intersect2d(startPoint, extensionDirection, pointOnDimLine, lineDirection);
1773
DrawUtil::Intersect2d(endPoint, extensionDirection, pointOnDimLine, lineDirection);
1775
drawDimensionLine(distancePath, endCross, lineAngle, startPosition,
1776
jointPositions[selected], labelRectangle, arrowCount, standardStyle,
1779
Base::Vector2d outsetPoint(
1780
standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
1781
? getIsoRefOutsetPoint(labelRectangle, selected == 1)// 0 = left, 1 = right
1782
: getAsmeRefOutsetPoint(labelRectangle, selected == 1));
1784
//add the reference line to the QPainterPath
1785
distancePath.moveTo(toQtGui(outsetPoint));
1786
distancePath.lineTo(toQtGui(refEndPoints[selected]));
1789
else if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) {
1790
// We may rotate the label so no leader and reference lines are needed
1791
double placementFactor = getIsoStandardLinePlacement(lineAngle);
1793
placementFactor > 0.0 ? DrawUtil::angleComposition(lineAngle, M_PI) : lineAngle;
1795
// Find out the projection of label center on the line with given angle
1796
Base::Vector2d labelProjection(
1798
+ Base::Vector2d::FromPolar(
1800
* (labelRectangle.Height() * 0.5 + getIsoDimensionLineSpacing()),
1801
lineAngle + M_PI_2));
1803
// Compute the dimensional line start and end crossings with (virtual) extension lines
1805
DrawUtil::Intersect2d(startPoint, extensionDirection, labelProjection, lineDirection);
1807
DrawUtil::Intersect2d(endPoint, extensionDirection, labelProjection, lineDirection);
1809
// Find linear coefficients of crossings
1810
double startPosition = arrowCount > 1 ? lineDirection * (startCross - endCross) : 0.0;
1811
double labelPosition = lineDirection * (labelProjection - endCross);
1813
drawDimensionLine(distancePath, endCross, lineAngle, startPosition, labelPosition,
1814
labelRectangle, arrowCount, standardStyle, flipArrows);
1817
else if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
1818
// Text must remain horizontal, but it may split the leader line
1820
DrawUtil::Intersect2d(startPoint, extensionDirection, labelCenter, lineDirection);
1821
endCross = DrawUtil::Intersect2d(endPoint, extensionDirection, labelCenter, lineDirection);
1823
// Find linear coefficients of crossings
1824
double startPosition = arrowCount > 1 ? lineDirection * (startCross - endCross) : 0.0;
1825
double labelPosition = lineDirection * (labelCenter - endCross);
1827
drawDimensionLine(distancePath, endCross, lineAngle, startPosition, labelPosition,
1828
labelRectangle, arrowCount, standardStyle, flipArrows);
1831
Base::Console().Error(
1832
"QGIVD::drawDistanceExecutive - this Standard&Style is not supported: %d\n",
1837
auto vp = static_cast<ViewProviderDimension*>(getViewProvider(getViewObject()));
1840
if (arrowCount > 0 && renderExtent >= ViewProviderDimension::REND_EXTENT_REDUCED) {
1841
double gapSize = 0.0;
1842
if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING
1843
|| standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
1844
double factor = vp->GapFactorASME.getValue();
1845
gapSize = Rez::appX(m_lineWidth * factor);
1847
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
1848
|| standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) {
1849
double factor = vp->GapFactorISO.getValue();
1850
gapSize = Rez::appX(m_lineWidth * factor);
1854
Base::Vector2d extensionOrigin;
1855
Base::Vector2d extensionTarget(computeExtensionLinePoints(
1856
endPoint, endCross, lineAngle + M_PI_2, getDefaultExtensionLineOverhang(), gapSize,
1858
//draw 1st extension line
1859
distancePath.moveTo(toQtGui(extensionOrigin));
1860
distancePath.lineTo(toQtGui(extensionTarget));
1862
if (arrowCount > 1) {
1863
extensionTarget = computeExtensionLinePoints(startPoint, startCross, lineAngle + M_PI_2,
1864
getDefaultExtensionLineOverhang(), gapSize,
1866
//draw second extension line
1867
distancePath.moveTo(toQtGui(extensionOrigin));
1868
distancePath.lineTo(toQtGui(extensionTarget));
1872
datumLabel->setTransformOriginPoint(datumLabel->boundingRect().center());
1873
datumLabel->setRotation(toQtDeg(labelAngle));
1875
dimLines->setPath(distancePath);
1878
void QGIViewDimension::drawRadiusExecutive(const Base::Vector2d& centerPoint,
1879
const Base::Vector2d& midPoint, double radius,
1880
double endAngle, double startRotation,
1881
const Base::BoundBox2d& labelRectangle,
1882
double centerOverhang, int standardStyle,
1883
int renderExtent, bool flipArrow) const
1885
QPainterPath radiusPath;
1887
Base::Vector2d labelCenter(labelRectangle.GetCenter());
1888
double labelAngle = 0.0;
1890
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
1891
|| standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING) {
1892
// The dimensional value text must stay horizontal
1893
Base::Vector2d jointDirections[2];
1895
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING) {
1896
jointDirections[0] = getIsoRefJointPoint(labelRectangle, false) - centerPoint;
1897
jointDirections[1] = getIsoRefJointPoint(labelRectangle, true) - centerPoint;
1900
jointDirections[0] = getAsmeRefJointPoint(labelRectangle, false) - centerPoint;
1901
jointDirections[1] = getAsmeRefJointPoint(labelRectangle, true) - centerPoint;
1904
double lineAngles[2];
1905
lineAngles[0] = jointDirections[0].Angle();
1906
lineAngles[1] = jointDirections[1].Angle();
1908
// Are there points on the arc, where line from center intersects it perpendicularly?
1909
double angleFactors[2];
1910
angleFactors[0] = getAnglePlacementFactor(lineAngles[0], endAngle, startRotation);
1911
angleFactors[1] = getAnglePlacementFactor(lineAngles[1], endAngle, startRotation);
1913
// Orient the leader line angle correctly towards the point on arc
1914
if (angleFactors[0] < 0.0) {
1915
lineAngles[0] = DrawUtil::angleComposition(lineAngles[0], M_PI);
1917
if (angleFactors[1] < 0.0) {
1918
lineAngles[1] = DrawUtil::angleComposition(lineAngles[1], M_PI);
1921
// Find the positions where the reference line attaches to the dimension line
1922
double jointPositions[2];
1923
jointPositions[0] = angleFactors[0] * jointDirections[0].Length() - radius;
1924
jointPositions[1] = angleFactors[1] * jointDirections[1].Length() - radius;
1926
Base::Vector2d targetPoints[2];
1927
targetPoints[0] = centerPoint + Base::Vector2d::FromPolar(radius, lineAngles[0]);
1928
targetPoints[1] = centerPoint + Base::Vector2d::FromPolar(radius, lineAngles[1]);
1930
Base::Vector2d arcPoint;
1932
if (angleFactors[0] || angleFactors[1]) {
1933
// At least from one of the reference line sides can run the leader line
1934
// perpendicularly to the arc, i.e. in direction to the center
1935
if (angleFactors[0] && angleFactors[1]) {
1936
// Both are acceptable, so choose the more convenient one
1937
double strikeFactors[2] = {0.0, 0.0};
1939
if (renderExtent >= ViewProviderDimension::REND_EXTENT_NORMAL) {
1940
std::vector<std::pair<double, bool>> lineMarking;
1941
constructDimensionLine(targetPoints[0], lineAngles[0], -radius,
1942
jointPositions[0], labelRectangle, 1, standardStyle,
1943
flipArrow, lineMarking);
1944
strikeFactors[0] = computeLineStrikeFactor(labelRectangle, targetPoints[0],
1945
lineAngles[0], lineMarking);
1947
lineMarking.clear();
1948
constructDimensionLine(targetPoints[1], lineAngles[1], -radius,
1949
jointPositions[1], labelRectangle, 1, standardStyle,
1950
flipArrow, lineMarking);
1951
strikeFactors[1] = computeLineStrikeFactor(labelRectangle, targetPoints[1],
1952
lineAngles[1], lineMarking);
1955
if (compareAngleStraightness(
1957
jointPositions[0] > 0.0 ? DrawUtil::angleComposition(lineAngles[0], M_PI)
1959
jointPositions[1] > 0.0 ? DrawUtil::angleComposition(lineAngles[1], M_PI)
1961
strikeFactors[0], strikeFactors[1])
1966
else if (angleFactors[1]) {
1970
arcPoint = targetPoints[selected];
1972
else {// Both joint points lay outside the vertical angles
1973
arcPoint = midPoint;
1975
if (labelCenter.x < arcPoint.x) {// Place the dimensional value left
1979
Base::Vector2d lineDirection(arcPoint - centerPoint - jointDirections[selected]);
1980
lineAngles[selected] = lineDirection.Angle();
1981
jointPositions[selected] = -lineDirection.Length();
1984
drawDimensionLine(radiusPath, arcPoint, lineAngles[selected],
1985
// If not reduced rendering and at least in one arc wedge, draw to center
1986
(angleFactors[0] || angleFactors[1])
1987
&& renderExtent >= ViewProviderDimension::REND_EXTENT_NORMAL
1988
? -radius - centerOverhang
1990
jointPositions[selected], labelRectangle, 1, standardStyle, flipArrow);
1992
Base::Vector2d outsetPoint(standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
1993
? getIsoRefOutsetPoint(labelRectangle, selected == 1)
1994
: getAsmeRefOutsetPoint(labelRectangle, selected == 1));
1996
radiusPath.moveTo(toQtGui(outsetPoint));
1997
radiusPath.lineTo(toQtGui(centerPoint + jointDirections[selected]));
1999
else if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) {
2000
// We may rotate the label so no reference line is needed
2002
double devAngle = computeLineAndLabelAngles(centerPoint, labelCenter,
2003
labelRectangle.Height() * 0.5
2004
+ getIsoDimensionLineSpacing(),
2005
lineAngle, labelAngle);
2007
// Is there point on the arc, where line from center intersects it perpendicularly?
2008
double angleFactor = getAnglePlacementFactor(lineAngle, endAngle, startRotation);
2009
if (angleFactor < 0.0) {
2010
lineAngle = DrawUtil::angleComposition(lineAngle, M_PI);
2013
Base::Vector2d arcPoint;
2014
double labelPosition;
2016
arcPoint = centerPoint + Base::Vector2d::FromPolar(radius, lineAngle);
2018
// Correct the label center distance projected on the leader line and subtract radius
2020
angleFactor * cos(devAngle) * ((labelCenter - centerPoint).Length()) - radius;
2023
// Leader line outside both arc wedges
2024
arcPoint = midPoint;
2026
devAngle = computeLineAndLabelAngles(arcPoint, labelCenter,
2027
labelRectangle.Height() * 0.5
2028
+ getIsoDimensionLineSpacing(),
2029
lineAngle, labelAngle);
2030
lineAngle = DrawUtil::angleComposition(lineAngle, M_PI);
2032
labelPosition = -cos(devAngle) * ((labelCenter - arcPoint).Length());
2035
drawDimensionLine(radiusPath, arcPoint, lineAngle,
2036
// If not reduced rendering and at least in one arc wedge, draw to center
2037
angleFactor && renderExtent >= ViewProviderDimension::REND_EXTENT_NORMAL
2038
? -radius - centerOverhang
2040
labelPosition, labelRectangle, 1, standardStyle, flipArrow);
2042
else if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
2043
// Text must remain horizontal, but it may split the leader line
2044
Base::Vector2d labelDirection(labelCenter - centerPoint);
2045
double lineAngle = labelDirection.Angle();
2047
// Is there point on the arc, where line from center intersects it perpendicularly?
2048
double angleFactor = getAnglePlacementFactor(lineAngle, endAngle, startRotation);
2049
if (angleFactor < 0) {
2050
lineAngle = DrawUtil::angleComposition(lineAngle, M_PI);
2053
Base::Vector2d arcPoint;
2054
double labelPosition;
2056
arcPoint = centerPoint + Base::Vector2d::FromPolar(radius, lineAngle);
2058
labelPosition = angleFactor * labelDirection.Length() - radius;
2061
// Leader line outside both arc wedges
2062
arcPoint = midPoint;
2064
labelDirection = arcPoint - labelCenter;
2065
lineAngle = labelDirection.Angle();
2066
labelPosition = -labelDirection.Length();
2069
drawDimensionLine(radiusPath, arcPoint, lineAngle,
2070
// If not reduced rendering and at least in one arc wedge, draw to center
2071
angleFactor && renderExtent >= ViewProviderDimension::REND_EXTENT_NORMAL
2072
? -radius - centerOverhang
2074
labelPosition, labelRectangle, 1, standardStyle, flipArrow);
2077
Base::Console().Error(
2078
"QGIVD::drawRadiusExecutive - this Standard&Style is not supported: %d\n",
2082
datumLabel->setTransformOriginPoint(datumLabel->boundingRect().center());
2083
datumLabel->setRotation(toQtDeg(labelAngle));
2085
dimLines->setPath(radiusPath);
2088
void QGIViewDimension::drawDistance(TechDraw::DrawViewDimension* dimension,
2089
ViewProviderDimension* viewProvider) const
2091
Base::BoundBox2d labelRectangle(
2092
fromQtGui(mapRectFromItem(datumLabel, datumLabel->boundingRect())));
2094
pointPair linePoints = dimension->getLinearPoints();
2095
const char* dimensionType = dimension->Type.getValueAsString();
2098
if (strcmp(dimensionType, "DistanceX") == 0) {
2101
else if (strcmp(dimensionType, "DistanceY") == 0) {
2105
lineAngle = (fromQtApp(linePoints.second()) - fromQtApp(linePoints.first())).Angle();
2108
int standardStyle = viewProvider->StandardAndStyle.getValue();
2109
int renderExtent = viewProvider->RenderingExtent.getValue();
2110
bool flipArrows = viewProvider->FlipArrowheads.getValue();
2113
if (dimension->AngleOverride.getValue()) {
2114
drawDistanceOverride(fromQtApp(linePoints.first()), fromQtApp(linePoints.second()),
2115
dimension->LineAngle.getValue() * M_PI / 180.0, labelRectangle,
2116
standardStyle, renderExtent, flipArrows,
2117
dimension->ExtensionAngle.getValue() * M_PI / 180.0);
2120
drawDistanceExecutive(fromQtApp(linePoints.extensionLineFirst()), fromQtApp(linePoints.extensionLineSecond()),
2121
lineAngle, labelRectangle, standardStyle, renderExtent, flipArrows);
2125
void QGIViewDimension::drawRadius(TechDraw::DrawViewDimension* dimension,
2126
ViewProviderDimension* viewProvider) const
2128
Base::BoundBox2d labelRectangle(
2129
fromQtGui(mapRectFromItem(datumLabel, datumLabel->boundingRect())));
2130
arcPoints curvePoints = dimension->getArcPoints();
2133
double startRotation;
2134
if (curvePoints.isArc) {
2136
(fromQtApp(curvePoints.arcEnds.second()) - fromQtApp(curvePoints.center)).Angle();
2138
(fromQtApp(curvePoints.arcEnds.first()) - fromQtApp(curvePoints.center)).Angle()
2141
if (startRotation != 0.0 && ((startRotation > 0.0) != curvePoints.arcCW)) {
2142
startRotation += curvePoints.arcCW ? +M_2PI : -M_2PI;
2145
else {// A circle arc covers the whole plane
2147
startRotation = -M_2PI;
2150
drawRadiusExecutive(
2151
fromQtApp(curvePoints.center), fromQtApp(curvePoints.midArc), curvePoints.radius, endAngle,
2152
startRotation, labelRectangle, 0.0, viewProvider->StandardAndStyle.getValue(),
2153
viewProvider->RenderingExtent.getValue(), viewProvider->FlipArrowheads.getValue());
2156
void QGIViewDimension::drawDiameter(TechDraw::DrawViewDimension* dimension,
2157
ViewProviderDimension* viewProvider) const
2159
Base::BoundBox2d labelRectangle(
2160
fromQtGui(mapRectFromItem(datumLabel, datumLabel->boundingRect())));
2161
Base::Vector2d labelCenter(labelRectangle.GetCenter());
2163
arcPoints curvePoints = dimension->getArcPoints();
2165
Base::Vector2d curveCenter(fromQtApp(curvePoints.center));
2166
double curveRadius = curvePoints.radius;
2168
int standardStyle = viewProvider->StandardAndStyle.getValue();
2169
int renderExtent = viewProvider->RenderingExtent.getValue();
2170
bool flipArrows = viewProvider->FlipArrowheads.getValue();
2172
if (renderExtent == ViewProviderDimension::REND_EXTENT_NORMAL) {
2173
// Draw diameter as one line crossing center touching two opposite circle points
2174
QPainterPath diameterPath;
2175
double labelAngle = 0.0;
2177
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
2178
|| standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING) {
2179
// The dimensional value text must stay horizontal
2180
Base::Vector2d jointDirections[2];
2182
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING) {
2183
jointDirections[0] = getIsoRefJointPoint(labelRectangle, false) - curveCenter;
2184
jointDirections[1] = getIsoRefJointPoint(labelRectangle, true) - curveCenter;
2187
jointDirections[0] = getAsmeRefJointPoint(labelRectangle, false) - curveCenter;
2188
jointDirections[1] = getAsmeRefJointPoint(labelRectangle, true) - curveCenter;
2191
// Find the angles of lines from the center
2192
double lineAngles[2];
2193
lineAngles[0] = jointDirections[0].Angle();
2194
lineAngles[1] = jointDirections[1].Angle();
2196
Base::Vector2d targetPoints[2];
2197
targetPoints[0] = curveCenter + Base::Vector2d::FromPolar(curveRadius, lineAngles[0]);
2198
targetPoints[1] = curveCenter + Base::Vector2d::FromPolar(curveRadius, lineAngles[1]);
2200
// Find the positions where the reference line attaches to the dimension line
2201
double jointPositions[2];
2202
jointPositions[0] = jointDirections[0].Length() - curveRadius;
2203
jointPositions[1] = jointDirections[1].Length() - curveRadius;
2205
// Select the placement, where the label is not obscured by the leader line
2206
double strikeFactors[2];
2208
std::vector<std::pair<double, bool>> lineMarking;
2209
constructDimensionLine(targetPoints[0], lineAngles[0], -curveRadius * 2.0,
2210
jointPositions[0], labelRectangle, 2, standardStyle, flipArrows,
2212
strikeFactors[0] = computeLineStrikeFactor(labelRectangle, targetPoints[0],
2213
lineAngles[0], lineMarking);
2215
lineMarking.clear();
2216
constructDimensionLine(targetPoints[1], lineAngles[1], -curveRadius * 2.0,
2217
jointPositions[1], labelRectangle, 2, standardStyle, flipArrows,
2219
strikeFactors[1] = computeLineStrikeFactor(labelRectangle, targetPoints[1],
2220
lineAngles[1], lineMarking);
2223
if (compareAngleStraightness(
2225
jointPositions[0] > 0.0 ? DrawUtil::angleComposition(lineAngles[0], M_PI)
2227
jointPositions[1] > 0.0 ? DrawUtil::angleComposition(lineAngles[1], M_PI)
2229
strikeFactors[0], strikeFactors[1])
2234
drawDimensionLine(diameterPath,
2236
+ Base::Vector2d::FromPolar(curveRadius, lineAngles[selected]),
2237
lineAngles[selected], -curveRadius * 2.0, jointPositions[selected],
2238
labelRectangle, 2, standardStyle, flipArrows);
2240
Base::Vector2d outsetPoint(standardStyle
2241
== ViewProviderDimension::STD_STYLE_ISO_REFERENCING
2242
? getIsoRefOutsetPoint(labelRectangle, selected == 1)
2243
: getAsmeRefOutsetPoint(labelRectangle, selected == 1));
2245
diameterPath.moveTo(toQtGui(outsetPoint));
2246
diameterPath.lineTo(toQtGui(curveCenter + jointDirections[selected]));
2248
else if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) {
2249
// We may rotate the label so no reference line is needed
2251
double devAngle = computeLineAndLabelAngles(curveCenter, labelCenter,
2252
labelRectangle.Height() * 0.5
2253
+ getIsoDimensionLineSpacing(),
2254
lineAngle, labelAngle);
2256
// Correct the label center distance projected on the leader line and subtract radius
2257
double labelPosition =
2258
cos(devAngle) * ((labelCenter - curveCenter).Length()) - curveRadius;
2260
drawDimensionLine(diameterPath,
2261
curveCenter + Base::Vector2d::FromPolar(curveRadius, lineAngle),
2262
lineAngle, -curveRadius * 2.0, labelPosition, labelRectangle, 2,
2263
standardStyle, flipArrows);
2265
else if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
2266
// Text must remain horizontal, but it may split the leader line
2267
double lineAngle = (labelCenter - curveCenter).Angle();
2268
//Base::Vector2d lineDirection(Base::Vector2d::FromPolar(1.0, lineAngle));
2271
diameterPath, curveCenter + Base::Vector2d::FromPolar(curveRadius, lineAngle),
2272
lineAngle, -curveRadius * 2.0, (labelCenter - curveCenter).Length() - curveRadius,
2273
labelRectangle, 2, standardStyle, flipArrows);
2276
Base::Console().Error("QGIVD::drawRadius - this Standard&Style is not supported: %d\n",
2280
datumLabel->setTransformOriginPoint(datumLabel->boundingRect().center());
2281
datumLabel->setRotation(toQtDeg(labelAngle));
2283
dimLines->setPath(diameterPath);
2285
else if (renderExtent >= ViewProviderDimension::REND_EXTENT_EXPANDED) {
2286
double lineAngle = (labelCenter - curveCenter).Angle();
2287
Base::Vector2d startPoint(curveCenter);
2288
Base::Vector2d endPoint(curveCenter);
2290
if ((lineAngle >= M_PI_4 && lineAngle <= 3.0 * M_PI_4)
2291
|| (lineAngle <= -M_PI_4 && lineAngle >= -3.0 * M_PI_4)) {
2292
// Horizontal dimension line
2293
startPoint.x -= curveRadius;
2294
endPoint.x += curveRadius;
2297
else {// Vertical dimension line
2298
startPoint.y -= curveRadius;
2299
endPoint.y += curveRadius;
2303
// lineAngle = DrawUtil::angleComposition((labelCenter - curveCenter).Angle(), +M_PI_2);
2304
// startPoint = curveCenter - Base::Vector2d::FromPolar(curveRadius, lineAngle);
2305
// endPoint = curveCenter + Base::Vector2d::FromPolar(curveRadius, lineAngle);
2307
drawDistanceExecutive(startPoint, endPoint, lineAngle, labelRectangle, standardStyle,
2308
ViewProviderDimension::REND_EXTENT_NORMAL, flipArrows);
2310
else if (renderExtent <= ViewProviderDimension::REND_EXTENT_REDUCED) {
2311
renderExtent = renderExtent <= ViewProviderDimension::REND_EXTENT_CONFINED
2312
? ViewProviderDimension::REND_EXTENT_REDUCED
2313
: ViewProviderDimension::REND_EXTENT_NORMAL;
2315
drawRadiusExecutive(curveCenter, Rez::guiX(curvePoints.midArc, true), curveRadius, M_PI,
2316
-M_2PI, labelRectangle, getDefaultExtensionLineOverhang(),
2317
standardStyle, renderExtent, flipArrows);
2321
void QGIViewDimension::drawAngle(TechDraw::DrawViewDimension* dimension,
2322
ViewProviderDimension* viewProvider) const
2324
QPainterPath anglePath;
2326
Base::BoundBox2d labelRectangle(
2327
fromQtGui(mapRectFromItem(datumLabel, datumLabel->boundingRect())));
2328
Base::Vector2d labelCenter(labelRectangle.GetCenter());
2329
double labelAngle = 0.0;
2331
anglePoints anglePoints = dimension->getAnglePoints();
2333
Base::Vector2d angleVertex = fromQtApp(anglePoints.vertex());
2334
Base::Vector2d startPoint = fromQtApp(anglePoints.first());
2335
Base::Vector2d endPoint = fromQtApp(anglePoints.second());
2337
double endAngle = (endPoint - angleVertex).Angle();
2338
double startAngle = (startPoint - angleVertex).Angle();
2341
int standardStyle = viewProvider->StandardAndStyle.getValue();
2342
int renderExtent = viewProvider->RenderingExtent.getValue();
2343
bool flipArrows = viewProvider->FlipArrowheads.getValue();
2345
int arrowCount = renderExtent >= ViewProviderDimension::REND_EXTENT_NORMAL
2346
|| renderExtent == ViewProviderDimension::REND_EXTENT_CONFINED
2350
// Inverted dimensions display reflex angles (fi > PI), regular ones oblique angles (fi <= PI/2)
2351
double startRotation =
2352
DrawUtil::angleDifference(startAngle, endAngle, dimension->Inverted.getValue());
2353
if (arrowCount < 2) {
2354
// For single arrow, the effective angle span is 0, but still we need to know
2355
// the angle orientation. Floating point positive/negative zero comes to rescue...
2356
startRotation = copysign(0.0, startRotation);
2359
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
2360
|| standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING) {
2361
// The dimensional value text must stay horizontal
2362
Base::Vector2d jointDirections[2];
2364
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING) {
2365
jointDirections[0] = getIsoRefJointPoint(labelRectangle, false) - angleVertex;
2366
jointDirections[1] = getIsoRefJointPoint(labelRectangle, true) - angleVertex;
2369
jointDirections[0] = getAsmeRefJointPoint(labelRectangle, false) - angleVertex;
2370
jointDirections[1] = getAsmeRefJointPoint(labelRectangle, true) - angleVertex;
2373
// Get radiuses of the angle dimension arcs
2375
arcRadii[0] = jointDirections[0].Length();
2376
arcRadii[1] = jointDirections[1].Length();
2378
// Compute the reference line joint angles
2379
double jointAngles[2];
2380
jointAngles[0] = jointDirections[0].Angle();
2381
jointAngles[1] = jointDirections[1].Angle();
2383
double handednessFactor = normalizeStartRotation(startRotation);
2384
double jointRotations[2];
2385
jointRotations[0] = handednessFactor * (jointAngles[0] - endAngle);
2386
jointRotations[1] = handednessFactor * (jointAngles[1] - endAngle);
2388
// Compare the offset with half of the rest of 2PI minus the angle and eventually fix the values
2389
if (fabs(jointRotations[0] - startRotation * 0.5) > M_PI) {
2390
jointRotations[0] += jointRotations[0] < 0.0 ? +M_2PI : -M_2PI;
2392
if (fabs(jointRotations[1] - startRotation * 0.5) > M_PI) {
2393
jointRotations[1] += jointRotations[1] < 0.0 ? +M_2PI : -M_2PI;
2396
// Compute the strike factors so we can choose the placement where value is not obscured by dimensional arc
2397
double strikeFactors[2];
2399
std::vector<std::pair<double, bool>> arcMarking;
2400
constructDimensionArc(angleVertex, arcRadii[0], endAngle, startRotation, handednessFactor,
2401
jointRotations[0], labelRectangle, arrowCount, standardStyle,
2402
flipArrows, arcMarking);
2404
computeArcStrikeFactor(labelRectangle, angleVertex, arcRadii[0], arcMarking);
2407
constructDimensionArc(angleVertex, arcRadii[1], endAngle, startRotation, handednessFactor,
2408
jointRotations[1], labelRectangle, arrowCount, standardStyle,
2409
flipArrows, arcMarking);
2411
computeArcStrikeFactor(labelRectangle, angleVertex, arcRadii[1], arcMarking);
2414
if (compareAngleStraightness(
2416
DrawUtil::angleComposition(
2417
jointAngles[0], handednessFactor * jointRotations[0] > 0.0 ? -M_PI_2 : +M_PI_2),
2418
DrawUtil::angleComposition(
2419
jointAngles[1], handednessFactor * jointRotations[1] > 0.0 ? -M_PI_2 : +M_PI_2),
2420
strikeFactors[0], strikeFactors[1])
2425
arcRadius = arcRadii[selected];
2426
startRotation = copysign(startRotation, -handednessFactor);
2428
drawDimensionArc(anglePath, angleVertex, arcRadius, endAngle, startRotation,
2429
jointAngles[selected], labelRectangle, arrowCount, standardStyle,
2432
Base::Vector2d outsetPoint(standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
2433
? getIsoRefOutsetPoint(labelRectangle, selected == 1)
2434
: getAsmeRefOutsetPoint(labelRectangle, selected == 1));
2436
anglePath.moveTo(toQtGui(outsetPoint));
2437
anglePath.lineTo(toQtGui(angleVertex + jointDirections[selected]));
2439
else if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) {
2440
// We may rotate the label so no leader and reference lines are needed
2441
Base::Vector2d labelDirection(labelCenter - angleVertex);
2442
double radiusAngle = labelDirection.Angle();
2444
labelAngle = DrawUtil::angleComposition(radiusAngle, M_PI_2);
2445
double placementFactor = getIsoStandardLinePlacement(labelAngle);
2447
placementFactor > 0.0 ? DrawUtil::angleComposition(labelAngle, M_PI) : labelAngle;
2449
arcRadius = labelDirection.Length()
2451
* (labelRectangle.Height() * 0.5 + getIsoDimensionLineSpacing());
2452
if (arcRadius < 0.0) {
2453
arcRadius = labelDirection.Length();
2456
drawDimensionArc(anglePath, angleVertex, arcRadius, endAngle, startRotation, radiusAngle,
2457
labelRectangle, arrowCount, standardStyle, flipArrows);
2459
else if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
2460
// Text must remain horizontal, but it may split the leader line
2461
Base::Vector2d labelDirection(labelCenter - angleVertex);
2462
arcRadius = labelDirection.Length();
2464
drawDimensionArc(anglePath, angleVertex, arcRadius, endAngle, startRotation,
2465
labelDirection.Angle(), labelRectangle, arrowCount, standardStyle,
2469
Base::Console().Error("QGIVD::drawAngle - this Standard&Style is not supported: %d\n",
2474
auto vp = static_cast<ViewProviderDimension*>(getViewProvider(getViewObject()));
2477
if (arrowCount > 0 && renderExtent >= ViewProviderDimension::REND_EXTENT_REDUCED) {
2478
double gapSize = 0.0;
2479
if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING
2480
|| standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
2481
double factor = vp->GapFactorASME.getValue();
2482
gapSize = Rez::appX(m_lineWidth * factor);
2484
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
2485
|| standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) {
2486
double factor = vp->GapFactorISO.getValue();
2487
gapSize = Rez::appX(m_lineWidth * factor);
2491
Base::Vector2d extensionOrigin;
2492
Base::Vector2d extensionTarget(computeExtensionLinePoints(
2493
endPoint, angleVertex + Base::Vector2d::FromPolar(arcRadius, endAngle), endAngle,
2494
getDefaultExtensionLineOverhang(), gapSize, extensionOrigin));
2495
anglePath.moveTo(toQtGui(extensionOrigin));
2496
anglePath.lineTo(toQtGui(extensionTarget));
2498
if (arrowCount > 1) {
2499
extensionTarget = computeExtensionLinePoints(
2500
startPoint, angleVertex + Base::Vector2d::FromPolar(arcRadius, startAngle),
2501
startAngle, getDefaultExtensionLineOverhang(), gapSize, extensionOrigin);
2502
anglePath.moveTo(toQtGui(extensionOrigin));
2503
anglePath.lineTo(toQtGui(extensionTarget));
2507
datumLabel->setTransformOriginPoint(datumLabel->boundingRect().center());
2508
datumLabel->setRotation(toQtDeg(labelAngle));
2510
dimLines->setPath(anglePath);
2513
QColor QGIViewDimension::prefNormalColor()
2515
setNormalColor(PreferencesGui::getAccessibleQColor(PreferencesGui::dimQColor()));
2516
ViewProviderDimension* vpDim = nullptr;
2517
Gui::ViewProvider* vp = getViewProvider(getDimFeat());
2519
vpDim = dynamic_cast<ViewProviderDimension*>(vp);
2521
App::Color fcColor = vpDim->Color.getValue();
2522
fcColor = Preferences::getAccessibleColor(fcColor);
2523
setNormalColor(fcColor.asValue<QColor>());
2526
return getNormalColor();
2529
//! find the closest isometric axis given an ortho vector
2530
Base::Vector3d QGIViewDimension::findIsoDir(Base::Vector3d ortho) const
2532
std::vector<Base::Vector3d> isoDirs = {Base::Vector3d(0.866, 0.5, 0.0), //iso X
2533
Base::Vector3d(-0.866, -0.5, 0.0),//iso -X
2534
Base::Vector3d(-0.866, 0.5, 0.0), //iso -Y?
2535
Base::Vector3d(0.866, -0.5, 0.0), //iso +Y?
2536
Base::Vector3d(0.0, -1.0, 0.0), //iso -Z
2537
Base::Vector3d(0.0, 1.0, 0.0)}; //iso Z
2538
std::vector<double> angles;
2539
for (auto& iso : isoDirs) {
2540
angles.push_back(ortho.GetAngle(iso));
2543
double min = angles[0];
2544
for (int i = 1; i < 6; i++) {
2545
if (angles[i] < min) {
2550
return isoDirs[idx];
2553
//! find the iso extension direction corresponding to an iso dist direction
2554
Base::Vector3d QGIViewDimension::findIsoExt(Base::Vector3d dir) const
2556
Base::Vector3d isoX(0.866, 0.5, 0.0); //iso X
2557
Base::Vector3d isoXr(-0.866, -0.5, 0.0);//iso -X
2558
Base::Vector3d isoY(-0.866, 0.5, 0.0); //iso -Y?
2559
Base::Vector3d isoYr(0.866, -0.5, 0.0); //iso +Y?
2560
Base::Vector3d isoZ(0.0, 1.0, 0.0); //iso Z
2561
Base::Vector3d isoZr(0.0, -1.0, 0.0); //iso -Z
2562
if (dir.IsEqual(isoX, FLT_EPSILON)) {
2565
else if (dir.IsEqual(-isoX, FLT_EPSILON)) {
2568
else if (dir.IsEqual(isoY, FLT_EPSILON)) {
2571
else if (dir.IsEqual(-isoY, FLT_EPSILON)) {
2574
else if (dir.IsEqual(isoZ, FLT_EPSILON)) {
2577
else if (dir.IsEqual(-isoZ, FLT_EPSILON)) {
2582
Base::Console().Message("QGIVD::findIsoExt - %s - input is not iso axis\n",
2583
getViewObject()->getNameInDocument());
2584
return Base::Vector3d(1, 0, 0);
2587
void QGIViewDimension::onPrettyChanged(int state)
2589
// Base::Console().Message("QGIVD::onPrettyChange(%d)\n", state);
2590
if (state == NORMAL) {
2593
else if (state == PRE) {
2596
else {//if state = SEL
2601
void QGIViewDimension::setPrettyPre()
2603
aHead1->setPrettyPre();
2604
aHead2->setPrettyPre();
2605
dimLines->setPrettyPre();
2608
void QGIViewDimension::setPrettySel()
2610
aHead1->setPrettySel();
2611
aHead2->setPrettySel();
2612
dimLines->setPrettySel();
2615
void QGIViewDimension::setPrettyNormal()
2617
aHead1->setPrettyNormal();
2618
aHead2->setPrettyNormal();
2619
dimLines->setPrettyNormal();
2622
void QGIViewDimension::drawBorder()
2624
//Dimensions have no border!
2625
// Base::Console().Message("TRACE - QGIViewDimension::drawBorder - doing nothing!\n");
2628
double QGIViewDimension::getDefaultExtensionLineOverhang() const
2630
// 8x Line Width according to ISO 129-1 Standard section 5.4, not specified by ASME Y14.5M
2631
return Rez::appX(m_lineWidth * 8.0);
2634
double QGIViewDimension::getDefaultArrowTailLength() const
2636
// Arrow length shall be equal to font height and both ISO and ASME seem
2637
// to have arrow tail twice the arrow length, so let's make it twice arrow size
2638
auto arrowSize = PreferencesGui::dimArrowSize();
2639
auto vp = static_cast<ViewProviderDimension*>(getViewProvider(getViewObject()));
2641
arrowSize = vp->Arrowsize.getValue();
2644
return arrowSize * 2.0;
2647
double QGIViewDimension::getDefaultIsoDimensionLineSpacing() const
2649
// Not specified directly, but seems to be 2x Line Width according to ISO 129-1 Annex A
2650
return Rez::appX(m_lineWidth * 2.0);
2653
// Returns the line spacing for ISO dimension based on the user inputted factor
2654
double QGIViewDimension::getIsoDimensionLineSpacing() const
2656
auto vp = static_cast<ViewProviderDimension*>(getViewProvider(getViewObject()));
2657
return Rez::appX(m_lineWidth * vp->LineSpacingFactorISO.getValue());
2660
double QGIViewDimension::getDefaultIsoReferenceLineOverhang() const
2662
// Not specified directly but seems to be exactly Line Width according to ISO 129-1 Annex A
2663
return Rez::appX(m_lineWidth * 1.0);
2666
double QGIViewDimension::getDefaultAsmeHorizontalLeaderLength() const
2668
// Not specified by ASME Y14.5M, this is a best guess
2669
return Rez::appX(m_lineWidth * 12);
2672
//frame, border, caption are never shown in QGIVD, so shouldn't be in bRect
2673
QRectF QGIViewDimension::boundingRect() const
2675
QRectF labelRect = mapFromItem(datumLabel, datumLabel->boundingRect()).boundingRect();
2676
QRectF linesRect = mapFromItem(dimLines, dimLines->boundingRect()).boundingRect();
2677
QRectF aHead1Rect = mapFromItem(aHead1, aHead1->boundingRect()).boundingRect();
2678
QRectF aHead2Rect = mapFromItem(aHead2, aHead2->boundingRect()).boundingRect();
2679
QRectF result(labelRect);
2680
result = result.united(linesRect);
2681
result = result.united(aHead1Rect);
2682
result = result.united(aHead2Rect);
2686
void QGIViewDimension::paint(QPainter* painter, const QStyleOptionGraphicsItem* option,
2689
QStyleOptionGraphicsItem myOption(*option);
2690
myOption.state &= ~QStyle::State_Selected;
2692
QPaintDevice* hw = painter->device();
2693
QSvgGenerator* svg = dynamic_cast<QSvgGenerator*>(hw);
2695
//double arrowSaveWidth = aHead1->getWidth();
2703
// painter->setPen(Qt::red);
2704
// painter->drawRect(boundingRect()); //good for debugging
2706
// QGIView::paint (painter, &myOption, widget);
2707
QGraphicsItemGroup::paint(painter, &myOption, widget);
2711
void QGIViewDimension::setSvgPens()
2713
double svgLineFactor = 3.0;//magic number. should be a setting somewhere.
2714
dimLines->setWidth(m_lineWidth / svgLineFactor);
2715
aHead1->setWidth(aHead1->getWidth() / svgLineFactor);
2716
aHead2->setWidth(aHead2->getWidth() / svgLineFactor);
2719
void QGIViewDimension::setPens()
2721
dimLines->setWidth(m_lineWidth);
2722
aHead1->setWidth(m_lineWidth);
2723
aHead2->setWidth(m_lineWidth);
2726
double QGIViewDimension::toDeg(double angle) { return angle * 180 / M_PI; }
2728
double QGIViewDimension::toQtRad(double angle) { return -angle; }
2730
double QGIViewDimension::toQtDeg(double angle) { return -angle * 180.0 / M_PI; }
2732
void QGIViewDimension::makeMarkC(double xPos, double yPos, QColor color) const
2734
QGIVertex* vItem = new QGIVertex(-1);
2735
vItem->setParentItem(const_cast<QGIViewDimension*>(this));
2736
vItem->setPos(xPos, yPos);
2737
vItem->setWidth(2.0);
2738
vItem->setRadius(20.0);
2739
vItem->setNormalColor(color);
2740
vItem->setFillColor(color);
2741
vItem->setPrettyNormal();
2742
vItem->setZValue(ZVALUE::VERTEX);
2745
#include <Mod/TechDraw/Gui/moc_QGIViewDimension.cpp>