2570 lines
101 KiB
C++
2570 lines
101 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2013 Luke Parry <l.parry@warwick.ac.uk> *
|
|
* *
|
|
* This file is part of the FreeCAD CAx development system. *
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Library General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2 of the License, or (at your option) any later version. *
|
|
* *
|
|
* This library is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU Library General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Library General Public *
|
|
* License along with this library; see the file COPYING.LIB. If not, *
|
|
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
|
* Suite 330, Boston, MA 02111-1307, USA *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "PreCompiled.h"
|
|
|
|
#ifdef FC_OS_WIN32
|
|
#define _USE_MATH_DEFINES //re Windows & M_PI issues
|
|
#endif
|
|
#include <cmath>
|
|
|
|
#ifndef _PreComp_
|
|
#include <BRep_Builder.hxx>
|
|
#include <TopoDS_Compound.hxx>
|
|
# include <TopoDS_Shape.hxx>
|
|
# include <TopoDS_Edge.hxx>
|
|
# include <TopoDS.hxx>
|
|
# include <BRepAdaptor_Curve.hxx>
|
|
# include <Precision.hxx>
|
|
|
|
# include <QApplication>
|
|
# include <QDebug>
|
|
# include <QGraphicsScene>
|
|
# include <QGraphicsSceneMouseEvent>
|
|
# include <QPainter>
|
|
# include <QPainterPath>
|
|
# include <QPaintDevice>
|
|
# include <QSvgGenerator>
|
|
|
|
#endif
|
|
|
|
#include <App/Application.h>
|
|
#include <App/Material.h>
|
|
#include <Base/Console.h>
|
|
#include <Base/Exception.h>
|
|
#include <Base/Parameter.h>
|
|
#include <Base/UnitsApi.h>
|
|
#include <Gui/Command.h>
|
|
|
|
#include <Mod/Part/App/PartFeature.h>
|
|
|
|
#include <Mod/TechDraw/App/DrawViewDimension.h>
|
|
#include <Mod/TechDraw/App/DrawViewPart.h>
|
|
#include <Mod/TechDraw/App/DrawUtil.h>
|
|
#include <Mod/TechDraw/App/Geometry.h>
|
|
|
|
#include "Rez.h"
|
|
#include "ZVALUE.h"
|
|
#include "PreferencesGui.h"
|
|
|
|
#include "QGCustomLabel.h"
|
|
#include "QGCustomBorder.h"
|
|
#include "QGCustomText.h"
|
|
#include "QGICaption.h"
|
|
#include "QGCustomImage.h"
|
|
|
|
#include "QGIArrow.h"
|
|
#include "QGIDimLines.h"
|
|
#include "QGIViewDimension.h"
|
|
#include "ViewProviderDimension.h"
|
|
#include "DrawGuiUtil.h"
|
|
#include "QGIVertex.h"
|
|
|
|
#define NORMAL 0
|
|
#define PRE 1
|
|
#define SEL 2
|
|
|
|
|
|
//TODO: hide the Qt coord system (+y down).
|
|
|
|
using namespace TechDraw;
|
|
using namespace TechDrawGui;
|
|
|
|
enum SnapMode{
|
|
NoSnap,
|
|
VerticalSnap,
|
|
HorizontalSnap
|
|
};
|
|
|
|
QGIDatumLabel::QGIDatumLabel()
|
|
{
|
|
verticalSep = false;
|
|
posX = 0;
|
|
posY = 0;
|
|
|
|
parent = nullptr;
|
|
|
|
setCacheMode(QGraphicsItem::NoCache);
|
|
setFlag(ItemSendsGeometryChanges, true);
|
|
setFlag(ItemIsMovable, true);
|
|
setFlag(ItemIsSelectable, true);
|
|
setAcceptHoverEvents(true);
|
|
setFiltersChildEvents(true);
|
|
|
|
m_dimText = new QGCustomText();
|
|
m_dimText->setTightBounding(true);
|
|
m_dimText->setParentItem(this);
|
|
m_tolTextOver = new QGCustomText();
|
|
m_tolTextOver->setTightBounding(true);
|
|
m_tolTextOver->setParentItem(this);
|
|
m_tolTextUnder = new QGCustomText();
|
|
m_tolTextUnder->setTightBounding(true);
|
|
m_tolTextUnder->setParentItem(this);
|
|
m_unitText = new QGCustomText();
|
|
m_unitText->setTightBounding(true);
|
|
m_unitText->setParentItem(this);
|
|
|
|
m_ctrl = false;
|
|
|
|
m_isFramed = false;
|
|
m_lineWidth = Rez::guiX(0.5);
|
|
}
|
|
|
|
QVariant QGIDatumLabel::itemChange(GraphicsItemChange change, const QVariant &value)
|
|
{
|
|
if (change == ItemSelectedHasChanged && scene()) {
|
|
if(isSelected()) {
|
|
setPrettySel();
|
|
} else {
|
|
setPrettyNormal();
|
|
}
|
|
update();
|
|
} else if(change == ItemPositionHasChanged && scene()) {
|
|
setLabelCenter();
|
|
Q_EMIT dragging(m_ctrl);
|
|
}
|
|
|
|
return QGraphicsItem::itemChange(change, value);
|
|
}
|
|
|
|
void QGIDatumLabel::mousePressEvent(QGraphicsSceneMouseEvent * event)
|
|
{
|
|
if(event->modifiers() & Qt::ControlModifier) {
|
|
m_ctrl = true;
|
|
}
|
|
|
|
QGraphicsItem::mousePressEvent(event);
|
|
}
|
|
|
|
void QGIDatumLabel::mouseMoveEvent(QGraphicsSceneMouseEvent * event)
|
|
{
|
|
QGraphicsItem::mouseMoveEvent(event);
|
|
}
|
|
|
|
void QGIDatumLabel::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
|
|
{
|
|
// Base::Console().Message("QGIDL::mouseReleaseEvent()\n");
|
|
m_ctrl = false;
|
|
if (QLineF(event->screenPos(), event->buttonDownScreenPos(Qt::LeftButton))
|
|
.length() > 0) {
|
|
if (scene() && this == scene()->mouseGrabberItem()) {
|
|
Q_EMIT dragFinished();
|
|
}
|
|
}
|
|
|
|
QGraphicsItem::mouseReleaseEvent(event);
|
|
}
|
|
|
|
void QGIDatumLabel::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
|
|
{
|
|
QGIViewDimension* qgivDimension = dynamic_cast<QGIViewDimension*>(parentItem());
|
|
if (qgivDimension == nullptr) {
|
|
qWarning() << "QGIDatumLabel::mouseDoubleClickEvent: No parent item";
|
|
return;
|
|
}
|
|
|
|
auto ViewProvider = dynamic_cast<ViewProviderDimension*>(qgivDimension->getViewProvider(qgivDimension->getViewObject()));
|
|
if (ViewProvider == nullptr) {
|
|
qWarning() << "QGIDatumLabel::mouseDoubleClickEvent: No valid view provider";
|
|
return;
|
|
}
|
|
|
|
ViewProvider->startDefaultEditMode();
|
|
QGraphicsItem::mouseDoubleClickEvent(event);
|
|
}
|
|
|
|
void QGIDatumLabel::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
|
|
{
|
|
Q_EMIT hover(true);
|
|
if (!isSelected()) {
|
|
setPrettyPre();
|
|
} else {
|
|
setPrettySel();
|
|
}
|
|
QGraphicsItem::hoverEnterEvent(event);
|
|
}
|
|
|
|
void QGIDatumLabel::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
|
|
{
|
|
Q_EMIT hover(false);
|
|
if (!isSelected()) {
|
|
setPrettyNormal();
|
|
} else {
|
|
setPrettySel();
|
|
}
|
|
|
|
QGraphicsItem::hoverLeaveEvent(event);
|
|
}
|
|
|
|
QRectF QGIDatumLabel::boundingRect() const
|
|
{
|
|
QRectF result = childrenBoundingRect();
|
|
result.adjust(-m_lineWidth*4.0, 0.0, 0.0, 0.0);
|
|
return result;
|
|
}
|
|
|
|
void QGIDatumLabel::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
|
{
|
|
Q_UNUSED(widget);
|
|
Q_UNUSED(painter);
|
|
QStyleOptionGraphicsItem myOption(*option);
|
|
myOption.state &= ~QStyle::State_Selected;
|
|
|
|
// painter->setPen(Qt::blue);
|
|
// painter->drawRect(boundingRect()); //good for debugging
|
|
|
|
if (m_isFramed) {
|
|
QPen prevPen = painter->pen();
|
|
QPen framePen(prevPen);
|
|
|
|
framePen.setWidthF(m_lineWidth);
|
|
framePen.setColor(m_dimText->defaultTextColor());
|
|
|
|
painter->setPen(framePen);
|
|
painter->drawRect(boundingRect());
|
|
painter->setPen(prevPen);
|
|
}
|
|
}
|
|
|
|
void QGIDatumLabel::setPosFromCenter(const double &xCenter, const double &yCenter)
|
|
{
|
|
prepareGeometryChange();
|
|
QGIViewDimension* qgivd = dynamic_cast<QGIViewDimension*>(parentItem());
|
|
if( qgivd == nullptr ) {
|
|
return;
|
|
}
|
|
const auto dim( dynamic_cast<TechDraw::DrawViewDimension *>(qgivd->getViewObject()) );
|
|
if( dim == nullptr ) {
|
|
return;
|
|
}
|
|
|
|
//set label's Qt position(top,left) given boundingRect center point
|
|
setPos(xCenter - m_dimText->boundingRect().width() / 2., yCenter - m_dimText->boundingRect().height() / 2.);
|
|
|
|
QString uText = m_unitText->toPlainText();
|
|
if ( (uText.size() > 0) &&
|
|
(uText.at(0) != QChar::fromLatin1(' ')) ) {
|
|
QString vText = m_dimText->toPlainText();
|
|
vText = vText + uText;
|
|
m_dimText->setPlainText(vText);
|
|
m_unitText->setPlainText(QString());
|
|
}
|
|
|
|
QRectF labelBox = m_dimText->boundingRect();
|
|
double right = labelBox.right();
|
|
double top = labelBox.top();
|
|
double bottom = labelBox.bottom();
|
|
double middle = (top + bottom) / 2.0;
|
|
|
|
//set unit position
|
|
QRectF unitBox = m_unitText->boundingRect();
|
|
double unitWidth = unitBox.width();
|
|
double unitRight = right + unitWidth;
|
|
// Set the m_unitText font *baseline* at same height as the m_dimText font baseline
|
|
m_unitText->setPos(right, 0.0);
|
|
|
|
//set tolerance position
|
|
QRectF overBox = m_tolTextOver->boundingRect();
|
|
double overWidth = overBox.width();
|
|
QRectF underBox = m_tolTextUnder->boundingRect();
|
|
double underWidth = underBox.width();
|
|
double width = underWidth;
|
|
if (overWidth > underWidth) {
|
|
width = overWidth;
|
|
}
|
|
double tolRight = unitRight + width;
|
|
|
|
// Adjust for difference in tight and original bounding box sizes, note the y-coord down system
|
|
QPointF tol_adj = m_tolTextOver->tightBoundingAdjust();
|
|
m_tolTextOver->justifyRightAt(tolRight + tol_adj.x(), middle - tol_adj.y(), false);
|
|
tol_adj = m_tolTextUnder->tightBoundingAdjust();
|
|
m_tolTextUnder->justifyRightAt(tolRight + tol_adj.x(), middle + overBox.height() - tol_adj.y(), false);
|
|
}
|
|
|
|
void QGIDatumLabel::setLabelCenter()
|
|
{
|
|
//save label's bRect center (posX,posY) given Qt position (top,left)
|
|
posX = x() + m_dimText->boundingRect().width() / 2.;
|
|
posY = y() + m_dimText->boundingRect().height() / 2.;
|
|
}
|
|
|
|
void QGIDatumLabel::setFont(QFont f)
|
|
{
|
|
prepareGeometryChange();
|
|
m_dimText->setFont(f);
|
|
m_unitText->setFont(f);
|
|
QFont tFont(f);
|
|
double fontSize = f.pixelSize();
|
|
double tolAdj = getTolAdjust();
|
|
tFont.setPixelSize((int) (fontSize * tolAdj));
|
|
m_tolTextOver->setFont(tFont);
|
|
m_tolTextUnder->setFont(tFont);
|
|
}
|
|
|
|
void QGIDatumLabel::setDimString(QString t)
|
|
{
|
|
prepareGeometryChange();
|
|
m_dimText->setPlainText(t);
|
|
}
|
|
|
|
void QGIDatumLabel::setDimString(QString t, qreal maxWidth)
|
|
{
|
|
prepareGeometryChange();
|
|
m_dimText->setPlainText(t);
|
|
m_dimText->setTextWidth(maxWidth);
|
|
}
|
|
|
|
void QGIDatumLabel::setToleranceString()
|
|
{
|
|
prepareGeometryChange();
|
|
QGIViewDimension* qgivd = dynamic_cast<QGIViewDimension*>(parentItem());
|
|
if( qgivd == nullptr ) {
|
|
return;
|
|
}
|
|
const auto dim( dynamic_cast<TechDraw::DrawViewDimension *>(qgivd->getViewObject()) );
|
|
if( dim == nullptr ) {
|
|
return;
|
|
// don't show if both are zero or if EqualTolerance is true
|
|
} else if (!dim->hasOverUnderTolerance() || dim->EqualTolerance.getValue() || dim->TheoreticalExact.getValue()) {
|
|
m_tolTextOver->hide();
|
|
m_tolTextUnder->hide();
|
|
// we must explicitly empty the text otherwise the frame drawn for
|
|
// TheoreticalExact would be as wide as necessary for the text
|
|
m_tolTextOver->setPlainText(QString());
|
|
m_tolTextUnder->setPlainText(QString());
|
|
return;
|
|
}
|
|
|
|
std::pair<std::string, std::string> labelTexts, unitTexts;
|
|
|
|
if (dim->ArbitraryTolerances.getValue()) {
|
|
labelTexts = dim->getFormattedToleranceValues(1); //copy tolerance spec
|
|
unitTexts.first = "";
|
|
unitTexts.second = "";
|
|
} else {
|
|
if (dim->isMultiValueSchema()) {
|
|
labelTexts = dim->getFormattedToleranceValues(0); //don't format multis
|
|
unitTexts.first = "";
|
|
unitTexts.second = "";
|
|
} else {
|
|
labelTexts = dim->getFormattedToleranceValues(1); // prefix value [unit] postfix
|
|
unitTexts = dim->getFormattedToleranceValues(2); //just the unit
|
|
}
|
|
}
|
|
|
|
if (labelTexts.first.empty()) {
|
|
m_tolTextUnder->hide();
|
|
} else {
|
|
m_tolTextUnder->setPlainText(QString::fromUtf8(labelTexts.first.c_str()));
|
|
m_tolTextUnder->show();
|
|
}
|
|
if (labelTexts.second.empty()) {
|
|
m_tolTextOver->hide();
|
|
}else {
|
|
m_tolTextOver->setPlainText(QString::fromUtf8(labelTexts.second.c_str()));
|
|
m_tolTextOver->show();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void QGIDatumLabel::setUnitString(QString t)
|
|
{
|
|
prepareGeometryChange();
|
|
if (t.isEmpty()) {
|
|
m_unitText->hide();
|
|
} else {
|
|
m_unitText->setPlainText(t);
|
|
m_unitText->show();
|
|
}
|
|
}
|
|
|
|
|
|
int QGIDatumLabel::getPrecision(void)
|
|
{
|
|
int precision;
|
|
bool global = false;
|
|
global = Preferences::useGlobalDecimals();
|
|
if (global) {
|
|
precision = Base::UnitsApi::getDecimals();
|
|
} else {
|
|
Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter().
|
|
GetGroup("BaseApp")->GetGroup("Preferences")->
|
|
GetGroup("Mod/TechDraw/Dimensions");
|
|
precision = hGrp->GetInt("AltDecimals", 2);
|
|
}
|
|
return precision;
|
|
}
|
|
|
|
double QGIDatumLabel::getTolAdjust(void)
|
|
{
|
|
double adjust;
|
|
Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
|
|
.GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Dimensions");
|
|
adjust = hGrp->GetFloat("TolSizeAdjust", 0.50);
|
|
return adjust;
|
|
}
|
|
|
|
|
|
void QGIDatumLabel::setPrettySel(void)
|
|
{
|
|
// Base::Console().Message("QGIDL::setPrettySel()\n");
|
|
m_dimText->setPrettySel();
|
|
m_tolTextOver->setPrettySel();
|
|
m_tolTextUnder->setPrettySel();
|
|
m_unitText->setPrettySel();
|
|
Q_EMIT setPretty(SEL);
|
|
}
|
|
|
|
void QGIDatumLabel::setPrettyPre(void)
|
|
{
|
|
// Base::Console().Message("QGIDL::setPrettyPre()\n");
|
|
m_dimText->setPrettyPre();
|
|
m_tolTextOver->setPrettyPre();
|
|
m_tolTextUnder->setPrettyPre();
|
|
m_unitText->setPrettyPre();
|
|
Q_EMIT setPretty(PRE);
|
|
}
|
|
|
|
void QGIDatumLabel::setPrettyNormal(void)
|
|
{
|
|
// Base::Console().Message("QGIDL::setPrettyNormal()\n");
|
|
m_dimText->setPrettyNormal();
|
|
m_tolTextOver->setPrettyNormal();
|
|
m_tolTextUnder->setPrettyNormal();
|
|
m_unitText->setPrettyNormal();
|
|
Q_EMIT setPretty(NORMAL);
|
|
}
|
|
|
|
void QGIDatumLabel::setColor(QColor c)
|
|
{
|
|
// Base::Console().Message("QGIDL::setColor(%s)\n", qPrintable(c.name()));
|
|
m_colNormal = c;
|
|
m_dimText->setColor(m_colNormal);
|
|
m_tolTextOver->setColor(m_colNormal);
|
|
m_tolTextUnder->setColor(m_colNormal);
|
|
m_unitText->setColor(m_colNormal);
|
|
}
|
|
|
|
//**************************************************************
|
|
QGIViewDimension::QGIViewDimension() :
|
|
dvDimension(nullptr),
|
|
hasHover(false),
|
|
m_lineWidth(0.0)
|
|
{
|
|
setHandlesChildEvents(false);
|
|
setFlag(QGraphicsItem::ItemIsMovable, false);
|
|
setFlag(QGraphicsItem::ItemIsSelectable, false);
|
|
setAcceptHoverEvents(false);
|
|
setCacheMode(QGraphicsItem::NoCache);
|
|
|
|
datumLabel = new QGIDatumLabel();
|
|
// datumLabel->m_parent = this; //for dialog setup eventually
|
|
|
|
addToGroup(datumLabel);
|
|
|
|
dimLines = new QGIDimLines();
|
|
addToGroup(dimLines);
|
|
|
|
aHead1 = new QGIArrow();
|
|
addToGroup(aHead1);
|
|
|
|
aHead2 = new QGIArrow();
|
|
addToGroup(aHead2);
|
|
|
|
datumLabel->setZValue(ZVALUE::DIMENSION);
|
|
aHead1->setZValue(ZVALUE::DIMENSION);
|
|
aHead2->setZValue(ZVALUE::DIMENSION);
|
|
dimLines->setZValue(ZVALUE::DIMENSION);
|
|
dimLines->setStyle(Qt::SolidLine);
|
|
|
|
// connecting the needed slots and signals
|
|
QObject::connect(
|
|
datumLabel, SIGNAL(dragging(bool)),
|
|
this , SLOT (datumLabelDragged(bool)));
|
|
|
|
QObject::connect(
|
|
datumLabel, SIGNAL(dragFinished()),
|
|
this , SLOT (datumLabelDragFinished()));
|
|
|
|
QObject::connect(
|
|
datumLabel, SIGNAL(selected(bool)),
|
|
this , SLOT (select(bool)));
|
|
|
|
QObject::connect(
|
|
datumLabel, SIGNAL(hover(bool)),
|
|
this , SLOT (hover(bool)));
|
|
|
|
QObject::connect(
|
|
datumLabel, SIGNAL(setPretty(int)),
|
|
this , SLOT (onPrettyChanged(int)));
|
|
|
|
setZValue(ZVALUE::DIMENSION); //note: this won't paint dimensions over another View if it stacks
|
|
//above this Dimension's parent view. need Layers?
|
|
m_border->hide();
|
|
m_label->hide();
|
|
}
|
|
|
|
QVariant QGIViewDimension::itemChange(GraphicsItemChange change, const QVariant &value)
|
|
{
|
|
if (change == ItemSelectedHasChanged && scene()) {
|
|
if(isSelected()) {
|
|
setSelected(false);
|
|
datumLabel->setSelected(true);
|
|
} else {
|
|
datumLabel->setSelected(false);
|
|
}
|
|
draw();
|
|
}
|
|
return QGIView::itemChange(change, value);
|
|
}
|
|
|
|
//Set selection state for this and it's children
|
|
void QGIViewDimension::setGroupSelection(bool b)
|
|
{
|
|
// Base::Console().Message("QGIVD::setGroupSelection(%d)\n",b);
|
|
setSelected(b);
|
|
datumLabel->setSelected(b);
|
|
dimLines->setSelected(b);
|
|
aHead1->setSelected(b);
|
|
aHead2->setSelected(b);
|
|
}
|
|
|
|
void QGIViewDimension::select(bool state)
|
|
{
|
|
Q_UNUSED(state)
|
|
// setSelected(state);
|
|
// draw();
|
|
}
|
|
|
|
//surrogate for hover enter (true), hover leave (false) events
|
|
void QGIViewDimension::hover(bool state)
|
|
{
|
|
hasHover = state;
|
|
draw();
|
|
}
|
|
|
|
void QGIViewDimension::setViewPartFeature(TechDraw::DrawViewDimension *obj)
|
|
{
|
|
// Base::Console().Message("QGIVD::setViewPartFeature()\n");
|
|
if(obj == nullptr)
|
|
return;
|
|
|
|
setViewFeature(static_cast<TechDraw::DrawView *>(obj));
|
|
|
|
// Set the QGIGroup Properties based on the DrawView
|
|
float x = Rez::guiX(obj->X.getValue());
|
|
float y = Rez::guiX(-obj->Y.getValue());
|
|
|
|
datumLabel->setPosFromCenter(x, y);
|
|
|
|
setNormalColorAll();
|
|
setPrettyNormal();
|
|
|
|
updateDim();
|
|
draw();
|
|
}
|
|
|
|
void QGIViewDimension::setNormalColorAll()
|
|
{
|
|
QColor qc = prefNormalColor();
|
|
datumLabel->setColor(qc);
|
|
dimLines->setNormalColor(qc);
|
|
aHead1->setNormalColor(qc);
|
|
aHead1->setFillColor(qc);
|
|
aHead2->setNormalColor(qc);
|
|
aHead2->setFillColor(qc);
|
|
}
|
|
|
|
void QGIViewDimension::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
|
|
{
|
|
// Base::Console().Message("QGIVDim::mouseReleaseEvent() - %s\n",getViewName());
|
|
QGraphicsItem::mouseReleaseEvent(event);
|
|
}
|
|
|
|
void QGIViewDimension::updateView(bool update)
|
|
{
|
|
Q_UNUSED(update);
|
|
auto dim( dynamic_cast<TechDraw::DrawViewDimension*>(getViewObject()) );
|
|
if( dim == nullptr )
|
|
return;
|
|
|
|
auto vp = static_cast<ViewProviderDimension*>(getViewProvider(getViewObject()));
|
|
if ( vp == nullptr ) {
|
|
return;
|
|
}
|
|
|
|
if (update||
|
|
dim->X.isTouched() ||
|
|
dim->Y.isTouched()) {
|
|
float x = Rez::guiX(dim->X.getValue());
|
|
float y = Rez::guiX(dim->Y.getValue());
|
|
datumLabel->setPosFromCenter(x,-y);
|
|
updateDim();
|
|
} else if(vp->Fontsize.isTouched() ||
|
|
vp->Font.isTouched()) {
|
|
updateDim();
|
|
} else if (vp->LineWidth.isTouched()) {
|
|
m_lineWidth = vp->LineWidth.getValue();
|
|
updateDim();
|
|
} else {
|
|
updateDim();
|
|
}
|
|
|
|
draw();
|
|
}
|
|
|
|
void QGIViewDimension::updateDim()
|
|
{
|
|
const auto dim( dynamic_cast<TechDraw::DrawViewDimension *>(getViewObject()) );
|
|
if( dim == nullptr ) {
|
|
return;
|
|
}
|
|
auto vp = static_cast<ViewProviderDimension*>(getViewProvider(getViewObject()));
|
|
if ( vp == nullptr ) {
|
|
return;
|
|
}
|
|
|
|
QString labelText= QString::fromUtf8(dim->getFormattedDimensionValue(1).c_str()); // pre value [unit] post
|
|
if (dim->isMultiValueSchema()) {
|
|
labelText = QString::fromUtf8(dim->getFormattedDimensionValue(0).c_str()); //don't format multis
|
|
}
|
|
|
|
QFont font = datumLabel->getFont();
|
|
font.setFamily(QString::fromUtf8(vp->Font.getValue()));
|
|
font.setPixelSize(calculateFontPixelSize(vp->Fontsize.getValue()));
|
|
datumLabel->setFont(font);
|
|
|
|
prepareGeometryChange();
|
|
datumLabel->setDimString(labelText);
|
|
datumLabel->setToleranceString();
|
|
datumLabel->setPosFromCenter(datumLabel->X(),datumLabel->Y());
|
|
|
|
datumLabel->setFramed(dim->TheoreticalExact.getValue());
|
|
datumLabel->setLineWidth(m_lineWidth);
|
|
}
|
|
|
|
void QGIViewDimension::datumLabelDragged(bool ctrl)
|
|
{
|
|
Q_UNUSED(ctrl);
|
|
draw();
|
|
}
|
|
|
|
void QGIViewDimension::datumLabelDragFinished()
|
|
{
|
|
auto dim( dynamic_cast<TechDraw::DrawViewDimension *>(getViewObject()) );
|
|
|
|
if( dim == nullptr ) {
|
|
return;
|
|
}
|
|
|
|
double x = Rez::appX(datumLabel->X()),
|
|
y = Rez::appX(datumLabel->Y());
|
|
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Drag Dimension"));
|
|
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.X = %f", dim->getNameInDocument(), x);
|
|
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Y = %f", dim->getNameInDocument(), -y);
|
|
Gui::Command::commitCommand();
|
|
}
|
|
|
|
//this is for formatting and finding centers, not display
|
|
QString QGIViewDimension::getLabelText(void)
|
|
{
|
|
QString result;
|
|
QString first = datumLabel->getDimText()->toPlainText();
|
|
QString second = datumLabel->getTolTextOver()->toPlainText();
|
|
QString third = datumLabel->getTolTextUnder()->toPlainText();
|
|
if (second.length() > third.length()) {
|
|
result = first + second;
|
|
} else {
|
|
result = first + third;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void QGIViewDimension::draw()
|
|
{
|
|
prepareGeometryChange();
|
|
if (!isVisible()) {
|
|
return;
|
|
}
|
|
|
|
TechDraw::DrawViewDimension *dim = dynamic_cast<TechDraw::DrawViewDimension *>(getViewObject());
|
|
if((!dim) || //nothing to draw, don't try
|
|
(!dim->isDerivedFrom(TechDraw::DrawViewDimension::getClassTypeId())) ||
|
|
(!dim->has2DReferences()) ) {
|
|
datumLabel->hide();
|
|
hide();
|
|
return;
|
|
}
|
|
|
|
const TechDraw::DrawViewPart *refObj = dim->getViewPart();
|
|
if (refObj == nullptr) {
|
|
return;
|
|
}
|
|
if(!refObj->hasGeometry()) { //nothing to draw yet (restoring)
|
|
datumLabel->hide();
|
|
hide();
|
|
return;
|
|
}
|
|
|
|
auto vp = static_cast<ViewProviderDimension*>(getViewProvider(getViewObject()));
|
|
if (vp == nullptr) {
|
|
datumLabel->show();
|
|
show();
|
|
return;
|
|
}
|
|
|
|
m_lineWidth = Rez::guiX(vp->LineWidth.getValue());
|
|
datumLabel->setRotation(0.0);
|
|
datumLabel->show();
|
|
|
|
resetArrows();
|
|
show();
|
|
|
|
if (vp->RenderingExtent.getValue() > ViewProviderDimension::REND_EXTENT_NONE) {
|
|
// We are expected to draw something, not just display the value
|
|
const char *dimType = dim->Type.getValueAsString();
|
|
|
|
if (strcmp(dimType, "Distance") == 0
|
|
|| strcmp(dimType, "DistanceX") == 0 || strcmp(dimType, "DistanceY") == 0) {
|
|
drawDistance(dim, vp);
|
|
}
|
|
else if (strcmp(dimType, "Diameter") == 0) {
|
|
drawDiameter(dim, vp);
|
|
}
|
|
else if (strcmp(dimType, "Radius") == 0) {
|
|
drawRadius(dim, vp);
|
|
}
|
|
else if (strcmp(dimType, "Angle") == 0 || strcmp(dimType, "Angle3Pt") == 0) {
|
|
drawAngle(dim, vp);
|
|
}
|
|
else {
|
|
Base::Console().Error("QGIVD::draw - this DimensionType is unknown: %s\n", dimType);
|
|
}
|
|
}
|
|
else {
|
|
// No dimension lines are drawn, the arrows are hidden
|
|
dimLines->setPath(QPainterPath());
|
|
drawArrows(0, nullptr, nullptr, false);
|
|
}
|
|
|
|
update();
|
|
if (parentItem()) {
|
|
//TODO: parent redraw still required with new frame/label??
|
|
parentItem()->update();
|
|
} else {
|
|
Base::Console().Log("INFO - QGIVD::draw - no parent to update\n");
|
|
}
|
|
}
|
|
|
|
double QGIViewDimension::getAnglePlacementFactor(double testAngle, double endAngle, double startRotation)
|
|
{
|
|
if (startRotation > 0.0) {
|
|
startRotation = -startRotation;
|
|
endAngle -= startRotation;
|
|
if (endAngle > M_PI) {
|
|
endAngle -= M_2PI;
|
|
}
|
|
}
|
|
|
|
if (testAngle > endAngle) {
|
|
testAngle -= M_2PI;
|
|
}
|
|
|
|
if (testAngle >= endAngle + startRotation) {
|
|
return +1.0;
|
|
}
|
|
|
|
testAngle += M_PI;
|
|
if (testAngle > endAngle) {
|
|
testAngle -= M_2PI;
|
|
}
|
|
|
|
if (testAngle >= endAngle + startRotation) {
|
|
return -1.0;
|
|
}
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
int QGIViewDimension::compareAngleStraightness(double straightAngle, double leftAngle, double rightAngle,
|
|
double leftStrikeFactor, double rightStrikeFactor)
|
|
{
|
|
double leftDelta = DrawUtil::angleComposition(M_PI, straightAngle - leftAngle);
|
|
double rightDelta = DrawUtil::angleComposition(rightAngle, -straightAngle);
|
|
|
|
if (fabs(leftDelta - rightDelta) <= Precision::Confusion()) {
|
|
return 0;
|
|
}
|
|
|
|
if (leftStrikeFactor == rightStrikeFactor) {
|
|
double leftBend = fabs(leftDelta);
|
|
double rightBend = fabs(rightDelta);
|
|
|
|
return DrawUtil::sgn(leftBend - rightBend);
|
|
}
|
|
|
|
return rightStrikeFactor > leftStrikeFactor ? -1 : +1;
|
|
}
|
|
|
|
double QGIViewDimension::getIsoStandardLinePlacement(double labelAngle)
|
|
{
|
|
// According to ISO 129-1 Standard Figure 23, the bordering angle is 1/2 PI, resp. -1/2 PI
|
|
return labelAngle < -M_PI/2.0 || labelAngle > +M_PI/2.0
|
|
? +1.0 : -1.0;
|
|
}
|
|
|
|
Base::Vector2d QGIViewDimension::getIsoRefOutsetPoint(const Base::BoundBox2d &labelRectangle, bool right) const
|
|
{
|
|
return Base::Vector2d(right ? labelRectangle.MinX - getDefaultIsoReferenceLineOverhang()
|
|
: labelRectangle.MaxX + getDefaultIsoReferenceLineOverhang(),
|
|
labelRectangle.MinY - getDefaultIsoDimensionLineSpacing());
|
|
}
|
|
|
|
Base::Vector2d QGIViewDimension::getIsoRefJointPoint(const Base::BoundBox2d &labelRectangle, bool right) const
|
|
{
|
|
return getIsoRefOutsetPoint(labelRectangle, !right);
|
|
}
|
|
|
|
Base::Vector2d QGIViewDimension::getAsmeRefOutsetPoint(const Base::BoundBox2d &labelRectangle, bool right) const
|
|
{
|
|
return Base::Vector2d(right ? labelRectangle.MaxX : labelRectangle.MinX,
|
|
labelRectangle.GetCenter().y);
|
|
}
|
|
|
|
Base::Vector2d QGIViewDimension::getAsmeRefJointPoint(const Base::BoundBox2d &labelRectangle, bool right) const
|
|
{
|
|
return Base::Vector2d(right ? labelRectangle.MaxX + getDefaultAsmeHorizontalLeaderLength()
|
|
: labelRectangle.MinX - getDefaultAsmeHorizontalLeaderLength(),
|
|
labelRectangle.GetCenter().y);
|
|
}
|
|
|
|
//find intersection of line L (through linePoint at angle lineAngle) and a line perpendicular to L
|
|
//passing through perpendicularPoint
|
|
//tricky vector algebra note:
|
|
//a*b is the magnitude of the projection of a onto b
|
|
//so we project a vector linePoint-perpendicularPoint onto unit vector in lineAngle direction giving
|
|
//the distance from linePoint to intersection, then make a displacement vector and add it to linePoint
|
|
Base::Vector2d QGIViewDimension::computePerpendicularIntersection(const Base::Vector2d &linePoint,
|
|
const Base::Vector2d &perpendicularPoint, double lineAngle)
|
|
{
|
|
return linePoint
|
|
+ Base::Vector2d::FromPolar((perpendicularPoint - linePoint)*Base::Vector2d::FromPolar(1.0, lineAngle),
|
|
lineAngle);
|
|
}
|
|
|
|
//calculate the end points of 1 extension line
|
|
//originPoint - a point on the distance line (end point)
|
|
//linePoint - point on dimension line that is perpendicular projection of distance line point
|
|
// onto dimension line
|
|
//1 extension line end point is the return value
|
|
//1 extension line end point is modified parameter startPoint
|
|
Base::Vector2d QGIViewDimension::computeExtensionLinePoints(const Base::Vector2d &originPoint,
|
|
const Base::Vector2d &linePoint, double hintAngle, double overhangSize,
|
|
double gapSize, Base::Vector2d &startPoint)
|
|
{
|
|
Base::Vector2d direction(linePoint - originPoint);
|
|
double rawLength = direction.Length();
|
|
|
|
if (rawLength <= Precision::Confusion()) {
|
|
direction = Base::Vector2d::FromPolar(1.0, hintAngle);
|
|
}
|
|
else {
|
|
direction = direction/rawLength;
|
|
}
|
|
|
|
if (overhangSize > rawLength - gapSize) {
|
|
// The extension line would be smaller than extension line overhang, keep it at least so long
|
|
startPoint = linePoint - overhangSize*direction;
|
|
}
|
|
else {
|
|
startPoint = linePoint - (rawLength - gapSize)*direction;
|
|
}
|
|
|
|
return linePoint + overhangSize*direction;
|
|
}
|
|
|
|
double QGIViewDimension::computeLineAndLabelAngles(const Base::Vector2d &rotationCenter,
|
|
const Base::Vector2d &labelCenter, double lineLabelDistance,
|
|
double &lineAngle, double &labelAngle)
|
|
{
|
|
// By default horizontal line and no label rotation
|
|
lineAngle = 0.0;
|
|
labelAngle = 0.0;
|
|
|
|
Base::Vector2d rawDirection(labelCenter - rotationCenter);
|
|
double rawDistance = rawDirection.Length();
|
|
if (rawDistance <= Precision::Confusion()) { // Almost single point, can't tell
|
|
return 0.0;
|
|
}
|
|
|
|
double rawAngle = rawDirection.Angle();
|
|
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 = getIsoStandardLinePlacement(rawAngle)*asin(lineLabelDistance/rawDistance);
|
|
lineAngle = DrawUtil::angleComposition(lineAngle, devAngle);
|
|
|
|
labelAngle = devAngle < 0.0 ? lineAngle : DrawUtil::angleComposition(lineAngle, M_PI);
|
|
|
|
return devAngle;
|
|
}
|
|
|
|
double QGIViewDimension::computeLineStrikeFactor(const Base::BoundBox2d &labelRectangle,
|
|
const Base::Vector2d &lineOrigin, double lineAngle,
|
|
const std::vector<std::pair<double, bool>> &drawMarking)
|
|
{
|
|
if (drawMarking.size() < 2) {
|
|
return 0.0;
|
|
}
|
|
|
|
std::vector<Base::Vector2d> intersectionPoints;
|
|
unsigned int startIndex = 0;
|
|
unsigned int currentIndex = 1;
|
|
|
|
while (currentIndex < drawMarking.size()) {
|
|
if (drawMarking[currentIndex].second != drawMarking[startIndex].second) {
|
|
if (drawMarking[startIndex].second) {
|
|
double segmentBase = drawMarking[startIndex].first;
|
|
double segmentLength = drawMarking[currentIndex].first - segmentBase;
|
|
|
|
DrawUtil::findLineSegmentRectangleIntersections(lineOrigin, lineAngle, segmentBase, segmentLength,
|
|
labelRectangle, intersectionPoints);
|
|
}
|
|
|
|
startIndex = currentIndex;
|
|
}
|
|
|
|
++currentIndex;
|
|
}
|
|
|
|
return intersectionPoints.size() >= 2 ? 1.0 : 0.0;
|
|
}
|
|
|
|
double QGIViewDimension::computeArcStrikeFactor(const Base::BoundBox2d &labelRectangle,
|
|
const Base::Vector2d &arcCenter, double arcRadius,
|
|
const std::vector<std::pair<double, bool>> &drawMarking)
|
|
{
|
|
if (drawMarking.size() < 1) {
|
|
return 0.0;
|
|
}
|
|
|
|
unsigned int entryIndex = 0;
|
|
while (entryIndex < drawMarking.size() && drawMarking[entryIndex].second) {
|
|
++entryIndex;
|
|
}
|
|
|
|
std::vector<Base::Vector2d> intersectionPoints;
|
|
|
|
if (entryIndex >= drawMarking.size()) {
|
|
DrawUtil::findCircleRectangleIntersections(arcCenter, arcRadius, labelRectangle, intersectionPoints);
|
|
}
|
|
else {
|
|
unsigned int startIndex = entryIndex;
|
|
unsigned int currentIndex = entryIndex;
|
|
do {
|
|
++currentIndex;
|
|
currentIndex %= drawMarking.size();
|
|
|
|
if (drawMarking[currentIndex].second != drawMarking[startIndex].second) {
|
|
if (drawMarking[startIndex].second) {
|
|
double arcAngle = drawMarking[startIndex].first;
|
|
double arcRotation = drawMarking[currentIndex].first - arcAngle;
|
|
if (arcRotation < 0.0) {
|
|
arcRotation += M_2PI;
|
|
}
|
|
|
|
DrawUtil::findCircularArcRectangleIntersections(arcCenter, arcRadius, arcAngle, arcRotation,
|
|
labelRectangle, intersectionPoints);
|
|
}
|
|
|
|
startIndex = currentIndex;
|
|
}
|
|
}
|
|
while (currentIndex != entryIndex);
|
|
}
|
|
|
|
return intersectionPoints.size() >= 2 ? 1.0 : 0.0;
|
|
}
|
|
|
|
double QGIViewDimension::normalizeStartPosition(double &startPosition, double &lineAngle)
|
|
{
|
|
if (startPosition > 0.0) {
|
|
startPosition = -startPosition;
|
|
lineAngle += M_PI;
|
|
return -1.0;
|
|
}
|
|
|
|
return +1.0;
|
|
}
|
|
|
|
double QGIViewDimension::normalizeStartRotation(double &startRotation)
|
|
{
|
|
if (copysign(1.0, startRotation) > 0.0) {
|
|
startRotation = -startRotation;
|
|
return -1.0;
|
|
}
|
|
|
|
return 1.0;
|
|
}
|
|
|
|
bool QGIViewDimension::constructDimensionLine(const Base::Vector2d &targetPoint, double lineAngle,
|
|
double startPosition, double jointPosition, const Base::BoundBox2d &labelRectangle,
|
|
int arrowCount, int standardStyle, bool flipArrows,
|
|
std::vector<std::pair<double, bool>> &outputMarking) const
|
|
{
|
|
// The start position > 0 is not expected, the caller must handle this
|
|
if (startPosition > 0.0) {
|
|
Base::Console().Error("QGIVD::constructDimLine - Start Position must not be positive! Received: %f\n",
|
|
startPosition);
|
|
return false;
|
|
}
|
|
|
|
double labelBorder = 0.0;
|
|
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) {
|
|
labelBorder = labelRectangle.Width()*0.5 + getDefaultIsoReferenceLineOverhang();
|
|
}
|
|
else if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
|
|
std::vector<Base::Vector2d> intersectionPoints;
|
|
DrawUtil::findLineRectangleIntersections(targetPoint, lineAngle, labelRectangle, intersectionPoints);
|
|
|
|
if (intersectionPoints.size() >= 2) {
|
|
labelBorder = (intersectionPoints[0] - labelRectangle.GetCenter()).Length();
|
|
}
|
|
}
|
|
|
|
bool autoFlipArrows = false;
|
|
if (jointPosition + labelBorder > 0.0) {
|
|
// If label sticks out, extend the dimension line beyond the end point (0.0)
|
|
DrawUtil::intervalMarkLinear(outputMarking, 0.0, jointPosition + labelBorder, true);
|
|
autoFlipArrows = true;
|
|
}
|
|
|
|
if (jointPosition - labelBorder < startPosition) {
|
|
DrawUtil::intervalMarkLinear(outputMarking, startPosition,
|
|
jointPosition - labelBorder - startPosition, true);
|
|
|
|
// For only one arrow and zero width line skip flipping, it already points correctly
|
|
if (arrowCount > 1 || startPosition < 0.0) {
|
|
autoFlipArrows = true;
|
|
}
|
|
}
|
|
|
|
flipArrows ^= autoFlipArrows;
|
|
if (!flipArrows
|
|
|| (standardStyle != ViewProviderDimension::STD_STYLE_ASME_INLINED
|
|
&& standardStyle != ViewProviderDimension::STD_STYLE_ASME_REFERENCING)) {
|
|
// If arrows point outside, or ASME standard is not followed,
|
|
// add the line part between start and end
|
|
DrawUtil::intervalMarkLinear(outputMarking, 0.0, startPosition, true);
|
|
}
|
|
|
|
// For ASME Inlined, cut out the part of line occupied by the value
|
|
if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
|
|
DrawUtil::intervalMarkLinear(outputMarking, jointPosition - labelBorder, labelBorder*2.0, false);
|
|
}
|
|
|
|
// Add the arrow tails - these are drawn always
|
|
double placementFactor = flipArrows ? +1.0 : -1.0;
|
|
DrawUtil::intervalMarkLinear(outputMarking, 0.0, placementFactor*getDefaultArrowTailLength(), true);
|
|
if (arrowCount > 1) {
|
|
DrawUtil::intervalMarkLinear(outputMarking, startPosition,
|
|
-placementFactor*getDefaultArrowTailLength(), true);
|
|
}
|
|
|
|
return flipArrows;
|
|
}
|
|
|
|
bool QGIViewDimension::constructDimensionArc(const Base::Vector2d &arcCenter, double arcRadius, double endAngle,
|
|
double startRotation, double handednessFactor, double jointRotation,
|
|
const Base::BoundBox2d &labelRectangle, int arrowCount, int standardStyle, bool flipArrows,
|
|
std::vector<std::pair<double, bool>> &outputMarking) const
|
|
{
|
|
// The start rotation > 0 is not expected, the caller must handle this
|
|
if (startRotation > 0.0) {
|
|
Base::Console().Error("QGIVD::constructDimArc - Start Rotation must not be positive! Received: %f\n",
|
|
startRotation);
|
|
return false;
|
|
}
|
|
|
|
double startDelta = 0.0;
|
|
double endDelta = 0.0;
|
|
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) {
|
|
double borderRadius = (labelRectangle.GetCenter() - arcCenter).Length();
|
|
|
|
if (borderRadius > arcRadius) {
|
|
borderRadius = arcRadius + getDefaultIsoDimensionLineSpacing();
|
|
}
|
|
else if (borderRadius < arcRadius) {
|
|
borderRadius = arcRadius - getDefaultIsoDimensionLineSpacing();
|
|
}
|
|
|
|
// ISO oriented labels are symmetrical along their center axis
|
|
startDelta = atan((labelRectangle.Width()*0.5 + getDefaultIsoReferenceLineOverhang())/borderRadius);
|
|
endDelta = startDelta;
|
|
}
|
|
else if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
|
|
std::vector<Base::Vector2d> intersectionPoints;
|
|
|
|
DrawUtil::findCircleRectangleIntersections(arcCenter, arcRadius, labelRectangle, intersectionPoints);
|
|
|
|
// We do not want to handle other cases than 2 intersection points - if so, act as if there were none
|
|
if (intersectionPoints.size() == 2) {
|
|
double zeroAngle = (labelRectangle.GetCenter()- arcCenter).Angle();
|
|
|
|
startDelta = DrawUtil::angleDifference(zeroAngle, (intersectionPoints[0] - arcCenter).Angle());
|
|
endDelta = DrawUtil::angleDifference(zeroAngle, (intersectionPoints[1] - arcCenter).Angle());
|
|
|
|
// End delta is the angle in the end point direction, start delta in the opposite
|
|
// Keep orientation and the computation sign in sync
|
|
if ((endDelta < 0.0) == (handednessFactor < 0.0)) {
|
|
std::swap(startDelta, endDelta);
|
|
}
|
|
|
|
startDelta = fabs(startDelta);
|
|
endDelta = fabs(endDelta);
|
|
}
|
|
}
|
|
|
|
bool autoFlipArrows = false;
|
|
if (jointRotation + endDelta > 0.0) {
|
|
// If label exceeds end angle ray, extend the dimension arc and flip arrows
|
|
DrawUtil::intervalMarkCircular(outputMarking, endAngle, handednessFactor*(jointRotation + endDelta), true);
|
|
autoFlipArrows = true;
|
|
}
|
|
|
|
if (jointRotation - startDelta < startRotation) {
|
|
DrawUtil::intervalMarkCircular(outputMarking, endAngle + handednessFactor*startRotation,
|
|
handednessFactor*(jointRotation - startDelta - startRotation), true);
|
|
|
|
// For only one arrow and zero width line skip flipping, it already points correctly
|
|
if (arrowCount > 1 || startRotation < 0.0) {
|
|
autoFlipArrows = true;
|
|
}
|
|
}
|
|
|
|
flipArrows ^= autoFlipArrows;
|
|
if (!flipArrows
|
|
|| (standardStyle != ViewProviderDimension::STD_STYLE_ASME_INLINED
|
|
&& standardStyle != ViewProviderDimension::STD_STYLE_ASME_REFERENCING)) {
|
|
// If arrows point outside, or ASME standard is not followed,
|
|
// add the arc part between start and end
|
|
DrawUtil::intervalMarkCircular(outputMarking, endAngle, handednessFactor*startRotation, true);
|
|
}
|
|
|
|
// For ASME Inlined, cut out the part of arc occupied by the value
|
|
if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
|
|
DrawUtil::intervalMarkCircular(outputMarking, endAngle + handednessFactor*(jointRotation - startDelta),
|
|
handednessFactor*(startDelta + endDelta), false);
|
|
}
|
|
|
|
// Add the arrow tails - these are drawn always
|
|
double tailDelta = arcRadius >= Precision::Confusion() ? getDefaultArrowTailLength()/arcRadius : M_PI_4;
|
|
double placementFactor = flipArrows ? +1.0 : -1.0;
|
|
|
|
DrawUtil::intervalMarkCircular(outputMarking, endAngle,
|
|
placementFactor*handednessFactor*tailDelta, true);
|
|
if (arrowCount > 1) {
|
|
DrawUtil::intervalMarkCircular(outputMarking, endAngle + handednessFactor*startRotation,
|
|
-placementFactor*handednessFactor*tailDelta, true);
|
|
}
|
|
|
|
return flipArrows;
|
|
}
|
|
|
|
void QGIViewDimension::resetArrows(void) const
|
|
{
|
|
aHead1->setDirMode(true);
|
|
aHead1->setRotation(0.0);
|
|
aHead1->setFlipped(false);
|
|
|
|
aHead2->setDirMode(true);
|
|
aHead2->setRotation(0.0);
|
|
aHead2->setFlipped(false);
|
|
}
|
|
|
|
void QGIViewDimension::drawArrows(int count, const Base::Vector2d positions[], double angles[], bool flipped) const
|
|
{
|
|
const int arrowCount = 2;
|
|
QGIArrow *arrows[arrowCount] = { aHead1, aHead2 };
|
|
|
|
arrowPositionsToFeature(positions);
|
|
|
|
for (int i = 0; i < arrowCount; ++i) {
|
|
QGIArrow *arrow = arrows[i];
|
|
|
|
if (positions && angles) {
|
|
arrow->setPos(toQtGui(positions[i]));
|
|
arrow->setDirection(toQtRad(angles[i]));
|
|
}
|
|
|
|
if (i >= count) {
|
|
arrow->hide();
|
|
continue;
|
|
}
|
|
|
|
arrow->setStyle(QGIArrow::getPrefArrowStyle());
|
|
arrow->setSize(QGIArrow::getPrefArrowSize());
|
|
arrow->setFlipped(flipped);
|
|
|
|
if (QGIArrow::getPrefArrowStyle() != 7) { // if not "None"
|
|
arrow->draw();
|
|
arrow->show();
|
|
}
|
|
else
|
|
arrow->hide();
|
|
}
|
|
}
|
|
|
|
void QGIViewDimension::arrowPositionsToFeature(const Base::Vector2d positions[]) const
|
|
{
|
|
auto dim( dynamic_cast<TechDraw::DrawViewDimension*>(getViewObject()) );
|
|
if( dim == nullptr )
|
|
return;
|
|
|
|
dim->saveArrowPositions(positions);
|
|
}
|
|
|
|
void QGIViewDimension::drawSingleLine(QPainterPath &painterPath, const Base::Vector2d &lineOrigin, double lineAngle,
|
|
double startPosition, double endPosition) const
|
|
{
|
|
if (endPosition == startPosition) {
|
|
return;
|
|
}
|
|
|
|
painterPath.moveTo(toQtGui(lineOrigin + Base::Vector2d::FromPolar(startPosition, lineAngle)));
|
|
painterPath.lineTo(toQtGui(lineOrigin + Base::Vector2d::FromPolar(endPosition, lineAngle)));
|
|
}
|
|
|
|
|
|
//adds line segments to painterPath from lineOrigin along lineAngle
|
|
//segment length is determined by drawMarking entries
|
|
void QGIViewDimension::drawMultiLine(QPainterPath &painterPath, const Base::Vector2d &lineOrigin, double lineAngle,
|
|
const std::vector<std::pair<double, bool>> &drawMarking) const
|
|
{
|
|
if (drawMarking.size() < 2) {
|
|
return;
|
|
}
|
|
|
|
unsigned int startIndex = 0;
|
|
unsigned int currentIndex = 1;
|
|
while (currentIndex < drawMarking.size()) {
|
|
if (drawMarking[currentIndex].second != drawMarking[startIndex].second) {
|
|
if (drawMarking[startIndex].second) {
|
|
drawSingleLine(painterPath, lineOrigin, lineAngle,
|
|
drawMarking[startIndex].first, drawMarking[currentIndex].first);
|
|
}
|
|
|
|
startIndex = currentIndex;
|
|
}
|
|
|
|
++currentIndex;
|
|
}
|
|
}
|
|
|
|
void QGIViewDimension::drawSingleArc(QPainterPath &painterPath, const Base::Vector2d &arcCenter, double arcRadius,
|
|
double startAngle, double endAngle) const
|
|
{
|
|
if (endAngle == startAngle) {
|
|
return;
|
|
}
|
|
if (endAngle < startAngle) {
|
|
endAngle += M_2PI;
|
|
}
|
|
|
|
QRectF qtArcRectangle(toQtGui(Base::BoundBox2d(arcCenter.x - arcRadius, arcCenter.y - arcRadius,
|
|
arcCenter.x + arcRadius, arcCenter.y + arcRadius)));
|
|
|
|
// In arc drawing are for some reason Qt's angles counterclockwise as in our computations...
|
|
painterPath.arcMoveTo(qtArcRectangle, toDeg(startAngle));
|
|
painterPath.arcTo(qtArcRectangle, toDeg(startAngle), toDeg(endAngle - startAngle));
|
|
}
|
|
|
|
void QGIViewDimension::drawMultiArc(QPainterPath &painterPath, const Base::Vector2d &arcCenter, double arcRadius,
|
|
const std::vector<std::pair<double, bool>> &drawMarking) const
|
|
{
|
|
if (drawMarking.size() < 1) {
|
|
return;
|
|
}
|
|
|
|
unsigned int entryIndex = 0;
|
|
while (entryIndex < drawMarking.size() && drawMarking[entryIndex].second) {
|
|
++entryIndex;
|
|
}
|
|
|
|
if (entryIndex >= drawMarking.size()) {
|
|
drawSingleArc(painterPath, arcCenter, arcRadius, 0, M_2PI);
|
|
return;
|
|
}
|
|
|
|
unsigned int startIndex = entryIndex;
|
|
unsigned int currentIndex = entryIndex;
|
|
do {
|
|
++currentIndex;
|
|
currentIndex %= drawMarking.size();
|
|
|
|
if (drawMarking[currentIndex].second != drawMarking[startIndex].second) {
|
|
if (drawMarking[startIndex].second) {
|
|
drawSingleArc(painterPath, arcCenter, arcRadius,
|
|
drawMarking[startIndex].first, drawMarking[currentIndex].first);
|
|
}
|
|
|
|
startIndex = currentIndex;
|
|
}
|
|
}
|
|
while (currentIndex != entryIndex);
|
|
}
|
|
|
|
|
|
//adds dimension line to painterPath
|
|
//dimension line starts at targetPoint and continues for a distance (startPosition?) along lineAngle
|
|
//jointPosition - distance of reference line from 1 extension line??
|
|
//lineAngle - Clockwise angle of distance line with horizontal
|
|
void QGIViewDimension::drawDimensionLine(QPainterPath &painterPath, const Base::Vector2d &targetPoint, double lineAngle,
|
|
double startPosition, double jointPosition, const Base::BoundBox2d &labelRectangle,
|
|
int arrowCount, int standardStyle, bool flipArrows) const
|
|
{
|
|
// Keep the convention start position <= 0
|
|
jointPosition *= normalizeStartPosition(startPosition, lineAngle);
|
|
|
|
std::vector<std::pair<double, bool>> drawMarks;
|
|
flipArrows = constructDimensionLine(targetPoint, lineAngle, startPosition, jointPosition,
|
|
labelRectangle, arrowCount, standardStyle, flipArrows,
|
|
drawMarks);
|
|
|
|
drawMultiLine(painterPath, targetPoint, lineAngle, drawMarks);
|
|
|
|
Base::Vector2d arrowPositions[2];
|
|
arrowPositions[0] = targetPoint;
|
|
arrowPositions[1] = targetPoint + Base::Vector2d::FromPolar(startPosition, lineAngle);
|
|
|
|
double arrowAngles[2];
|
|
arrowAngles[0] = lineAngle;
|
|
arrowAngles[1] = lineAngle + M_PI;
|
|
|
|
drawArrows(arrowCount, arrowPositions, arrowAngles, flipArrows);
|
|
}
|
|
|
|
void QGIViewDimension::drawDimensionArc(QPainterPath &painterPath, const Base::Vector2d &arcCenter, double arcRadius,
|
|
double endAngle, double startRotation, double jointAngle,
|
|
const Base::BoundBox2d &labelRectangle,
|
|
int arrowCount, int standardStyle, bool flipArrows) const
|
|
{
|
|
// Keep the convention start rotation <= 0
|
|
double handednessFactor = normalizeStartRotation(startRotation);
|
|
|
|
// Split the rest of 2PI minus the angle and assign joint offset so > 0 is closer to end arc side
|
|
double jointRotation = handednessFactor*(jointAngle - endAngle);
|
|
if (fabs(jointRotation - startRotation*0.5) > M_PI) {
|
|
jointRotation += jointRotation < 0.0 ? +M_2PI : -M_2PI;
|
|
}
|
|
|
|
std::vector<std::pair<double, bool>> drawMarks;
|
|
flipArrows = constructDimensionArc(arcCenter, arcRadius, endAngle, startRotation, handednessFactor, jointRotation,
|
|
labelRectangle, arrowCount, standardStyle, flipArrows,
|
|
drawMarks);
|
|
|
|
drawMultiArc(painterPath, arcCenter, arcRadius, drawMarks);
|
|
|
|
Base::Vector2d arrowPositions[2];
|
|
arrowPositions[0] = arcCenter + Base::Vector2d::FromPolar(arcRadius, endAngle);
|
|
arrowPositions[1] = arcCenter + Base::Vector2d::FromPolar(arcRadius, endAngle + handednessFactor*startRotation);
|
|
|
|
double arrowAngles[2];
|
|
arrowAngles[0] = endAngle + handednessFactor*M_PI_2;
|
|
arrowAngles[1] = endAngle + handednessFactor*(startRotation - M_PI_2);
|
|
|
|
drawArrows(arrowCount, arrowPositions, arrowAngles, flipArrows);
|
|
}
|
|
|
|
//draw any of 3 distance dimension types
|
|
//startPoint, endPoint - ends of actual distance line
|
|
//lineAngle - angle of actual line with horizontal
|
|
//target points - projection of reference line ends on to extension line
|
|
//startCross & endCross - real intersection of extension lines and dimension line
|
|
//dimension line - main annotation line
|
|
//reference line - line under dimension text in referenced styles
|
|
//joint points - ends of reference line
|
|
void QGIViewDimension::drawDistanceExecutive(const Base::Vector2d &startPoint, const Base::Vector2d &endPoint,
|
|
double lineAngle, const Base::BoundBox2d &labelRectangle,
|
|
int standardStyle, int renderExtent, bool flipArrows) const
|
|
{
|
|
QPainterPath distancePath;
|
|
|
|
Base::Vector2d labelCenter(labelRectangle.GetCenter());
|
|
double labelAngle = 0.0;
|
|
|
|
//startCross and endCross are points where extension line intersects dimension line
|
|
Base::Vector2d startCross;
|
|
Base::Vector2d endCross;
|
|
int arrowCount = renderExtent >= ViewProviderDimension::REND_EXTENT_NORMAL
|
|
|| renderExtent == ViewProviderDimension::REND_EXTENT_CONFINED
|
|
? 2 : 1;
|
|
|
|
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
|
|
|| standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING) {
|
|
// The dimensional value text must stay horizontal in these styles
|
|
|
|
//jointPoints are the ends of the reference line
|
|
Base::Vector2d jointPoints[2];
|
|
|
|
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING) {
|
|
jointPoints[0] = getIsoRefJointPoint(labelRectangle, false);
|
|
jointPoints[1] = getIsoRefJointPoint(labelRectangle, true);
|
|
}
|
|
else {
|
|
jointPoints[0] = getAsmeRefJointPoint(labelRectangle, false);
|
|
jointPoints[1] = getAsmeRefJointPoint(labelRectangle, true);
|
|
}
|
|
|
|
//targetPoints are the projection of reference line endpoints onto endPoint's extension line
|
|
Base::Vector2d targetPoints[2];
|
|
targetPoints[0] = computePerpendicularIntersection(jointPoints[0], endPoint, lineAngle);
|
|
targetPoints[1] = computePerpendicularIntersection(jointPoints[1], endPoint, lineAngle);
|
|
|
|
// Compute and normalize (i.e. make < 0) the start position
|
|
Base::Vector2d lineDirection(Base::Vector2d::FromPolar(1.0, lineAngle));
|
|
double startPosition = arrowCount > 1 ? lineDirection*(startPoint - targetPoints[0]) : 0.0;
|
|
lineDirection *= normalizeStartPosition(startPosition, lineAngle);
|
|
|
|
// Find the positions where the reference line attaches to the dimension line
|
|
//jointPoints are the ends of the reference line
|
|
//targetPoints - projection of reference line on to extension line
|
|
//jointPositions - displacement of jointPoints from ext line
|
|
double jointPositions[2];
|
|
jointPositions[0] = lineDirection*(jointPoints[0] - targetPoints[0]);
|
|
jointPositions[1] = lineDirection*(jointPoints[1] - targetPoints[1]);
|
|
|
|
// Orient the leader line angle correctly towards the target point
|
|
double angles[2];
|
|
angles[0] = jointPositions[0] > 0.0 ? DrawUtil::angleComposition(lineAngle, M_PI) : lineAngle;
|
|
angles[1] = jointPositions[1] > 0.0 ? DrawUtil::angleComposition(lineAngle, M_PI) : lineAngle;
|
|
|
|
// Select the placement, where the label is not obscured by the leader line
|
|
// or (if both behave the same) the one that bends the reference line less
|
|
double strikeFactors[2];
|
|
|
|
std::vector<std::pair<double, bool>> lineMarking;
|
|
constructDimensionLine(targetPoints[0], lineAngle, startPosition, jointPositions[0],
|
|
labelRectangle, arrowCount, standardStyle, flipArrows, lineMarking);
|
|
strikeFactors[0] = computeLineStrikeFactor(labelRectangle, targetPoints[0], lineAngle, lineMarking);
|
|
|
|
lineMarking.clear();
|
|
constructDimensionLine(targetPoints[1], lineAngle, startPosition, jointPositions[1],
|
|
labelRectangle, arrowCount, standardStyle, flipArrows, lineMarking);
|
|
strikeFactors[1] = computeLineStrikeFactor(labelRectangle, targetPoints[1], lineAngle, lineMarking);
|
|
|
|
int selected = compareAngleStraightness(0.0, angles[0], angles[1], strikeFactors[0], strikeFactors[1]);
|
|
if (selected == 0) {
|
|
// Select the side closer, so the label is on the outer side of the dimension line
|
|
Base::Vector2d perpendicularDir(lineDirection.Perpendicular());
|
|
if (fabs((jointPoints[0] - endPoint)*perpendicularDir)
|
|
> fabs((jointPoints[1] - endPoint)*perpendicularDir)) {
|
|
selected = 1;
|
|
}
|
|
}
|
|
else if (selected < 0) {
|
|
selected = 0;
|
|
}
|
|
|
|
//find points where extension lines meet dimension line
|
|
endCross = targetPoints[selected];
|
|
startCross = targetPoints[selected] + Base::Vector2d::FromPolar(startPosition, lineAngle);
|
|
|
|
drawDimensionLine(distancePath, endCross, lineAngle, startPosition, jointPositions[selected],
|
|
labelRectangle, arrowCount, standardStyle, flipArrows);
|
|
|
|
Base::Vector2d outsetPoint(standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
|
|
? getIsoRefOutsetPoint(labelRectangle, selected == 1) // 0 = left, 1 = right
|
|
: getAsmeRefOutsetPoint(labelRectangle, selected == 1));
|
|
|
|
//add the reference line to the QPainterPath
|
|
distancePath.moveTo(toQtGui(outsetPoint));
|
|
distancePath.lineTo(toQtGui(jointPoints[selected]));
|
|
}
|
|
|
|
else if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) {
|
|
// We may rotate the label so no leader and reference lines are needed
|
|
double placementFactor = getIsoStandardLinePlacement(lineAngle);
|
|
labelAngle = placementFactor > 0.0 ? DrawUtil::angleComposition(lineAngle, M_PI) : lineAngle;
|
|
|
|
// Find out the projection of label center on the line with given angle
|
|
Base::Vector2d labelProjection(
|
|
labelCenter
|
|
+ Base::Vector2d::FromPolar(
|
|
placementFactor*(labelRectangle.Height()*0.5
|
|
+ getDefaultIsoDimensionLineSpacing()),
|
|
lineAngle + M_PI_2));
|
|
|
|
// Compute the dimensional line start and end crossings with (virtual) extension lines
|
|
//check for isometric direction and if iso compute non-perpendicular intersection of dim line and ext lines
|
|
Base::Vector2d lineDirection(Base::Vector2d::FromPolar(1.0, lineAngle));
|
|
startCross = computePerpendicularIntersection(labelProjection, startPoint, lineAngle);
|
|
endCross = computePerpendicularIntersection(labelProjection, endPoint, lineAngle);
|
|
|
|
// Find linear coefficients of crossings
|
|
double startPosition = arrowCount > 1 ? lineDirection*(startCross - endCross) : 0.0;
|
|
double labelPosition = lineDirection*(labelProjection - endCross);
|
|
|
|
drawDimensionLine(distancePath, endCross, lineAngle, startPosition, labelPosition,
|
|
labelRectangle, arrowCount, standardStyle, flipArrows);
|
|
}
|
|
|
|
else if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
|
|
// Text must remain horizontal, but it may split the leader line
|
|
Base::Vector2d lineDirection(Base::Vector2d::FromPolar(1.0, lineAngle));
|
|
startCross = computePerpendicularIntersection(labelCenter, startPoint, lineAngle);
|
|
endCross = computePerpendicularIntersection(labelCenter, endPoint, lineAngle);
|
|
|
|
// Find linear coefficients of crossings
|
|
double startPosition = arrowCount > 1 ? lineDirection*(startCross - endCross) : 0.0;
|
|
double labelPosition = lineDirection*(labelCenter - endCross);
|
|
|
|
drawDimensionLine(distancePath, endCross, lineAngle, startPosition, labelPosition,
|
|
labelRectangle, arrowCount, standardStyle, flipArrows);
|
|
}
|
|
else {
|
|
Base::Console().Error("QGIVD::drawDistanceExecutive - this Standard&Style is not supported: %d\n",
|
|
standardStyle);
|
|
arrowCount = 0;
|
|
}
|
|
|
|
if (arrowCount > 0 && renderExtent >= ViewProviderDimension::REND_EXTENT_REDUCED) {
|
|
double gapSize = 0.0;
|
|
if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING
|
|
|| standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
|
|
gapSize = getDefaultAsmeExtensionLineGap();
|
|
}
|
|
|
|
Base::Vector2d extensionOrigin;
|
|
Base::Vector2d extensionTarget(computeExtensionLinePoints(endPoint, endCross, lineAngle + M_PI_2,
|
|
getDefaultExtensionLineOverhang(), gapSize, extensionOrigin));
|
|
//draw 1st extension line
|
|
distancePath.moveTo(toQtGui(extensionOrigin));
|
|
distancePath.lineTo(toQtGui(extensionTarget));
|
|
|
|
if (arrowCount > 1) {
|
|
extensionTarget = computeExtensionLinePoints(startPoint, startCross, lineAngle + M_PI_2,
|
|
getDefaultExtensionLineOverhang(), gapSize, extensionOrigin);
|
|
//draw second extension line
|
|
distancePath.moveTo(toQtGui(extensionOrigin));
|
|
distancePath.lineTo(toQtGui(extensionTarget));
|
|
}
|
|
}
|
|
|
|
datumLabel->setTransformOriginPoint(datumLabel->boundingRect().center());
|
|
datumLabel->setRotation(toQtDeg(labelAngle));
|
|
|
|
dimLines->setPath(distancePath);
|
|
}
|
|
|
|
//draw any of 3 distance dimension types with user override of dimension and extension line directions
|
|
//startPoint, endPoint - ends of actual distance line
|
|
//lineAngle - desired angle of dimension line with horizontal
|
|
//extensionAngle - desired angle of extension lines with horizontal
|
|
void QGIViewDimension::drawDistanceOverride(const Base::Vector2d &startPoint, const Base::Vector2d &endPoint,
|
|
double lineAngle, const Base::BoundBox2d &labelRectangle,
|
|
int standardStyle, int renderExtent, bool flipArrows, double extensionAngle) const
|
|
{
|
|
QPainterPath distancePath;
|
|
|
|
Base::Vector2d labelCenter(labelRectangle.GetCenter());
|
|
double labelAngle = 0.0;
|
|
|
|
//startCross and endCross are points where extension lines intersect dimension line
|
|
Base::Vector2d startCross;
|
|
Base::Vector2d endCross;
|
|
Base::Vector2d lineDirection(Base::Vector2d::FromPolar(1.0, lineAngle));
|
|
Base::Vector2d extensionDirection(Base::Vector2d::FromPolar(1.0, extensionAngle));
|
|
|
|
int arrowCount = renderExtent >= ViewProviderDimension::REND_EXTENT_NORMAL
|
|
|| renderExtent == ViewProviderDimension::REND_EXTENT_CONFINED
|
|
? 2 : 1;
|
|
|
|
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
|
|
|| standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING) {
|
|
// The dimensional value text must stay horizontal in these styles
|
|
|
|
//refEndPoints are the ends of the reference line
|
|
Base::Vector2d refEndPoints[2];
|
|
|
|
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING) {
|
|
refEndPoints[0] = getIsoRefJointPoint(labelRectangle, false);
|
|
refEndPoints[1] = getIsoRefJointPoint(labelRectangle, true);
|
|
}
|
|
else {
|
|
refEndPoints[0] = getAsmeRefJointPoint(labelRectangle, false);
|
|
refEndPoints[1] = getAsmeRefJointPoint(labelRectangle, true);
|
|
}
|
|
|
|
//targetPoints are the projection of reference line endpoints onto endPoint's extension line
|
|
Base::Vector2d targetPoints[2];
|
|
targetPoints[0] = DrawUtil::Intersect2d(refEndPoints[0], lineDirection, endPoint, extensionDirection);
|
|
targetPoints[1] = DrawUtil::Intersect2d(refEndPoints[1], lineDirection, endPoint, extensionDirection);
|
|
Base::Vector2d pointOnStartExtension = DrawUtil::Intersect2d(endPoint, lineDirection, startPoint, extensionDirection);
|
|
double startPosition = arrowCount > 1 ? lineDirection*( pointOnStartExtension - endPoint) : 0.0;
|
|
|
|
// Compute and normalize (i.e. make < 0) the start position
|
|
lineDirection *= normalizeStartPosition(startPosition, lineAngle);
|
|
|
|
// Find the positions where the reference line attaches to the dimension line
|
|
//refEndPoints are the ends of the reference line
|
|
//targetPoints - projection of reference line on to extension line
|
|
//jointPositions - displacement of refEndPoints from extension line
|
|
double jointPositions[2];
|
|
jointPositions[0] = lineDirection*(refEndPoints[0] - targetPoints[0]);
|
|
jointPositions[1] = lineDirection*(refEndPoints[1] - targetPoints[1]);
|
|
|
|
// Orient the leader line angle correctly towards the target point
|
|
double angles[2];
|
|
angles[0] = jointPositions[0] > 0.0 ? DrawUtil::angleComposition(lineAngle, M_PI) : lineAngle;
|
|
angles[1] = jointPositions[1] > 0.0 ? DrawUtil::angleComposition(lineAngle, M_PI) : lineAngle;
|
|
|
|
// Select the placement, where the label is not obscured by the leader line
|
|
// or (if both behave the same) the one that bends the reference line less
|
|
double strikeFactors[2];
|
|
|
|
std::vector<std::pair<double, bool>> lineMarking;
|
|
constructDimensionLine(targetPoints[0], lineAngle, startPosition, jointPositions[0],
|
|
labelRectangle, arrowCount, standardStyle, flipArrows, lineMarking);
|
|
strikeFactors[0] = computeLineStrikeFactor(labelRectangle, targetPoints[0], lineAngle, lineMarking);
|
|
|
|
lineMarking.clear();
|
|
constructDimensionLine(targetPoints[1], lineAngle, startPosition, jointPositions[1],
|
|
labelRectangle, arrowCount, standardStyle, flipArrows, lineMarking);
|
|
strikeFactors[1] = computeLineStrikeFactor(labelRectangle, targetPoints[1], lineAngle, lineMarking);
|
|
|
|
int selected = compareAngleStraightness(0.0, angles[0], angles[1], strikeFactors[0], strikeFactors[1]);
|
|
if (selected == 0) {
|
|
// Select the side closer, so the label is on the outer side of the dimension line
|
|
Base::Vector2d perpendicularDir(lineDirection.Perpendicular());
|
|
if (fabs((refEndPoints[0] - endPoint)*perpendicularDir)
|
|
> fabs((refEndPoints[1] - endPoint)*perpendicularDir)) {
|
|
selected = 1;
|
|
}
|
|
}
|
|
else if (selected < 0) {
|
|
selected = 0;
|
|
}
|
|
|
|
//find points where extension lines meet dimension line
|
|
Base::Vector2d pointOnDimLine(refEndPoints[selected].x, refEndPoints[selected].y);
|
|
startCross = DrawUtil::Intersect2d(startPoint, extensionDirection, pointOnDimLine, lineDirection);
|
|
endCross = DrawUtil::Intersect2d(endPoint, extensionDirection, pointOnDimLine, lineDirection);
|
|
|
|
drawDimensionLine(distancePath, endCross, lineAngle, startPosition, jointPositions[selected],
|
|
labelRectangle, arrowCount, standardStyle, flipArrows);
|
|
|
|
Base::Vector2d outsetPoint(standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
|
|
? getIsoRefOutsetPoint(labelRectangle, selected == 1) // 0 = left, 1 = right
|
|
: getAsmeRefOutsetPoint(labelRectangle, selected == 1));
|
|
|
|
//add the reference line to the QPainterPath
|
|
distancePath.moveTo(toQtGui(outsetPoint));
|
|
distancePath.lineTo(toQtGui(refEndPoints[selected]));
|
|
}
|
|
|
|
else if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) {
|
|
// We may rotate the label so no leader and reference lines are needed
|
|
double placementFactor = getIsoStandardLinePlacement(lineAngle);
|
|
labelAngle = placementFactor > 0.0 ? DrawUtil::angleComposition(lineAngle, M_PI) : lineAngle;
|
|
|
|
// Find out the projection of label center on the line with given angle
|
|
Base::Vector2d labelProjection(
|
|
labelCenter
|
|
+ Base::Vector2d::FromPolar(
|
|
placementFactor*(labelRectangle.Height()*0.5
|
|
+ getDefaultIsoDimensionLineSpacing()),
|
|
lineAngle + M_PI_2));
|
|
|
|
// Compute the dimensional line start and end crossings with (virtual) extension lines
|
|
startCross = DrawUtil::Intersect2d(startPoint, extensionDirection, labelProjection, lineDirection);
|
|
endCross = DrawUtil::Intersect2d(endPoint, extensionDirection, labelProjection, lineDirection);
|
|
|
|
// Find linear coefficients of crossings
|
|
double startPosition = arrowCount > 1 ? lineDirection*(startCross - endCross) : 0.0;
|
|
double labelPosition = lineDirection*(labelProjection - endCross);
|
|
|
|
drawDimensionLine(distancePath, endCross, lineAngle, startPosition, labelPosition,
|
|
labelRectangle, arrowCount, standardStyle, flipArrows);
|
|
}
|
|
|
|
else if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
|
|
// Text must remain horizontal, but it may split the leader line
|
|
startCross = DrawUtil::Intersect2d(startPoint, extensionDirection, labelCenter, lineDirection);
|
|
endCross = DrawUtil::Intersect2d(endPoint, extensionDirection, labelCenter, lineDirection);
|
|
|
|
// Find linear coefficients of crossings
|
|
double startPosition = arrowCount > 1 ? lineDirection*(startCross - endCross) : 0.0;
|
|
double labelPosition = lineDirection*(labelCenter - endCross);
|
|
|
|
drawDimensionLine(distancePath, endCross, lineAngle, startPosition, labelPosition,
|
|
labelRectangle, arrowCount, standardStyle, flipArrows);
|
|
}
|
|
else {
|
|
Base::Console().Error("QGIVD::drawDistanceExecutive - this Standard&Style is not supported: %d\n",
|
|
standardStyle);
|
|
arrowCount = 0;
|
|
}
|
|
|
|
if (arrowCount > 0 && renderExtent >= ViewProviderDimension::REND_EXTENT_REDUCED) {
|
|
double gapSize = 0.0;
|
|
if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING
|
|
|| standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
|
|
gapSize = getDefaultAsmeExtensionLineGap();
|
|
}
|
|
|
|
Base::Vector2d extensionOrigin;
|
|
Base::Vector2d extensionTarget(computeExtensionLinePoints(endPoint, endCross, lineAngle + M_PI_2,
|
|
getDefaultExtensionLineOverhang(), gapSize, extensionOrigin));
|
|
//draw 1st extension line
|
|
distancePath.moveTo(toQtGui(extensionOrigin));
|
|
distancePath.lineTo(toQtGui(extensionTarget));
|
|
|
|
if (arrowCount > 1) {
|
|
extensionTarget = computeExtensionLinePoints(startPoint, startCross, lineAngle + M_PI_2,
|
|
getDefaultExtensionLineOverhang(), gapSize, extensionOrigin);
|
|
//draw second extension line
|
|
distancePath.moveTo(toQtGui(extensionOrigin));
|
|
distancePath.lineTo(toQtGui(extensionTarget));
|
|
}
|
|
}
|
|
|
|
datumLabel->setTransformOriginPoint(datumLabel->boundingRect().center());
|
|
datumLabel->setRotation(toQtDeg(labelAngle));
|
|
|
|
dimLines->setPath(distancePath);
|
|
}
|
|
|
|
void QGIViewDimension::drawRadiusExecutive(const Base::Vector2d ¢erPoint, const Base::Vector2d &midPoint,
|
|
double radius, double endAngle, double startRotation,
|
|
const Base::BoundBox2d &labelRectangle, double centerOverhang,
|
|
int standardStyle, int renderExtent, bool flipArrow) const
|
|
{
|
|
QPainterPath radiusPath;
|
|
|
|
Base::Vector2d labelCenter(labelRectangle.GetCenter());
|
|
double labelAngle = 0.0;
|
|
|
|
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
|
|
|| standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING) {
|
|
// The dimensional value text must stay horizontal
|
|
Base::Vector2d jointDirections[2];
|
|
|
|
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING) {
|
|
jointDirections[0] = getIsoRefJointPoint(labelRectangle, false) - centerPoint;
|
|
jointDirections[1] = getIsoRefJointPoint(labelRectangle, true) - centerPoint;
|
|
}
|
|
else {
|
|
jointDirections[0] = getAsmeRefJointPoint(labelRectangle, false) - centerPoint;
|
|
jointDirections[1] = getAsmeRefJointPoint(labelRectangle, true) - centerPoint;
|
|
}
|
|
|
|
double lineAngles[2];
|
|
lineAngles[0] = jointDirections[0].Angle();
|
|
lineAngles[1] = jointDirections[1].Angle();
|
|
|
|
// Are there points on the arc, where line from center intersects it perpendicularly?
|
|
double angleFactors[2];
|
|
angleFactors[0] = getAnglePlacementFactor(lineAngles[0], endAngle, startRotation);
|
|
angleFactors[1] = getAnglePlacementFactor(lineAngles[1], endAngle, startRotation);
|
|
|
|
// Orient the leader line angle correctly towards the point on arc
|
|
if (angleFactors[0] < 0.0) lineAngles[0] = DrawUtil::angleComposition(lineAngles[0], M_PI);
|
|
if (angleFactors[1] < 0.0) lineAngles[1] = DrawUtil::angleComposition(lineAngles[1], M_PI);
|
|
|
|
// Find the positions where the reference line attaches to the dimension line
|
|
double jointPositions[2];
|
|
jointPositions[0] = angleFactors[0]*jointDirections[0].Length() - radius;
|
|
jointPositions[1] = angleFactors[1]*jointDirections[1].Length() - radius;
|
|
|
|
Base::Vector2d targetPoints[2];
|
|
targetPoints[0] = centerPoint + Base::Vector2d::FromPolar(radius, lineAngles[0]);
|
|
targetPoints[1] = centerPoint + Base::Vector2d::FromPolar(radius, lineAngles[1]);
|
|
|
|
Base::Vector2d arcPoint;
|
|
int selected = 0;
|
|
if (angleFactors[0] || angleFactors[1]) {
|
|
// 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 (angleFactors[0] && angleFactors[1]) {
|
|
// Both are acceptable, so choose the more convenient one
|
|
double strikeFactors[2] = { 0.0, 0.0 };
|
|
|
|
if (renderExtent >= ViewProviderDimension::REND_EXTENT_NORMAL) {
|
|
std::vector<std::pair<double, bool>> lineMarking;
|
|
constructDimensionLine(targetPoints[0], lineAngles[0], -radius, jointPositions[0],
|
|
labelRectangle, 1, standardStyle, flipArrow, lineMarking);
|
|
strikeFactors[0] = computeLineStrikeFactor(labelRectangle, targetPoints[0],
|
|
lineAngles[0], lineMarking);
|
|
|
|
lineMarking.clear();
|
|
constructDimensionLine(targetPoints[1], lineAngles[1], -radius, jointPositions[1],
|
|
labelRectangle, 1, standardStyle, flipArrow, lineMarking);
|
|
strikeFactors[1] = computeLineStrikeFactor(labelRectangle, targetPoints[1],
|
|
lineAngles[1], lineMarking);
|
|
}
|
|
|
|
if (compareAngleStraightness(0.0,
|
|
jointPositions[0] > 0.0 ? DrawUtil::angleComposition(lineAngles[0], M_PI) : lineAngles[0],
|
|
jointPositions[1] > 0.0 ? DrawUtil::angleComposition(lineAngles[1], M_PI) : lineAngles[1],
|
|
strikeFactors[0], strikeFactors[1]) > 0) {
|
|
selected = 1;
|
|
}
|
|
}
|
|
else if (angleFactors[1]) {
|
|
selected = 1;
|
|
}
|
|
|
|
arcPoint = targetPoints[selected];
|
|
}
|
|
else { // Both joint points lay outside the vertical angles
|
|
arcPoint = midPoint;
|
|
|
|
if (labelCenter.x < arcPoint.x) { // Place the dimensional value left
|
|
selected = 1;
|
|
}
|
|
|
|
Base::Vector2d lineDirection(arcPoint - centerPoint - jointDirections[selected]);
|
|
lineAngles[selected] = lineDirection.Angle();
|
|
jointPositions[selected] = -lineDirection.Length();
|
|
}
|
|
|
|
drawDimensionLine(radiusPath, arcPoint, lineAngles[selected],
|
|
// If not reduced rendering and at least in one arc wedge, draw to center
|
|
(angleFactors[0] || angleFactors[1])
|
|
&& renderExtent >= ViewProviderDimension::REND_EXTENT_NORMAL
|
|
? -radius - centerOverhang : 0.0,
|
|
jointPositions[selected], labelRectangle, 1, standardStyle, flipArrow);
|
|
|
|
Base::Vector2d outsetPoint(standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
|
|
? getIsoRefOutsetPoint(labelRectangle, selected == 1)
|
|
: getAsmeRefOutsetPoint(labelRectangle, selected == 1));
|
|
|
|
radiusPath.moveTo(toQtGui(outsetPoint));
|
|
radiusPath.lineTo(toQtGui(centerPoint + jointDirections[selected]));
|
|
}
|
|
else if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) {
|
|
// We may rotate the label so no reference line is needed
|
|
double lineAngle;
|
|
double devAngle = computeLineAndLabelAngles(centerPoint, labelCenter,
|
|
labelRectangle.Height()*0.5 + getDefaultIsoDimensionLineSpacing(), lineAngle, labelAngle);
|
|
|
|
// Is there point on the arc, where line from center intersects it perpendicularly?
|
|
double angleFactor = getAnglePlacementFactor(lineAngle, endAngle, startRotation);
|
|
if (angleFactor < 0.0) {
|
|
lineAngle = DrawUtil::angleComposition(lineAngle, M_PI);
|
|
}
|
|
|
|
Base::Vector2d arcPoint;
|
|
double labelPosition;
|
|
if (angleFactor) {
|
|
arcPoint = centerPoint + Base::Vector2d::FromPolar(radius, lineAngle);
|
|
|
|
// Correct the label center distance projected on the leader line and subtract radius
|
|
labelPosition = angleFactor*cos(devAngle)*((labelCenter - centerPoint).Length()) - radius;
|
|
}
|
|
else {
|
|
// Leader line outside both arc wedges
|
|
arcPoint = midPoint;
|
|
|
|
devAngle = computeLineAndLabelAngles(arcPoint, labelCenter,
|
|
labelRectangle.Height()*0.5 + getDefaultIsoDimensionLineSpacing(), lineAngle, labelAngle);
|
|
lineAngle = DrawUtil::angleComposition(lineAngle, M_PI);
|
|
|
|
labelPosition = -cos(devAngle)*((labelCenter - arcPoint).Length());
|
|
}
|
|
|
|
drawDimensionLine(radiusPath, arcPoint, lineAngle,
|
|
// If not reduced rendering and at least in one arc wedge, draw to center
|
|
angleFactor && renderExtent >= ViewProviderDimension::REND_EXTENT_NORMAL
|
|
? -radius - centerOverhang : 0.0,
|
|
labelPosition, labelRectangle, 1, standardStyle, flipArrow);
|
|
}
|
|
else if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
|
|
// Text must remain horizontal, but it may split the leader line
|
|
Base::Vector2d labelDirection(labelCenter - centerPoint);
|
|
double lineAngle = labelDirection.Angle();
|
|
|
|
// Is there point on the arc, where line from center intersects it perpendicularly?
|
|
double angleFactor = getAnglePlacementFactor(lineAngle, endAngle, startRotation);
|
|
if (angleFactor < 0) {
|
|
lineAngle = DrawUtil::angleComposition(lineAngle, M_PI);
|
|
}
|
|
|
|
Base::Vector2d arcPoint;
|
|
double labelPosition;
|
|
if (angleFactor) {
|
|
arcPoint = centerPoint + Base::Vector2d::FromPolar(radius, lineAngle);
|
|
|
|
labelPosition = angleFactor*labelDirection.Length() - radius;
|
|
}
|
|
else {
|
|
// Leader line outside both arc wedges
|
|
arcPoint = midPoint;
|
|
|
|
labelDirection = arcPoint - labelCenter;
|
|
lineAngle = labelDirection.Angle();
|
|
labelPosition = -labelDirection.Length();
|
|
}
|
|
|
|
drawDimensionLine(radiusPath, arcPoint, lineAngle,
|
|
// If not reduced rendering and at least in one arc wedge, draw to center
|
|
angleFactor && renderExtent >= ViewProviderDimension::REND_EXTENT_NORMAL
|
|
? -radius - centerOverhang : 0.0,
|
|
labelPosition, labelRectangle, 1, standardStyle, flipArrow);
|
|
}
|
|
else {
|
|
Base::Console().Error("QGIVD::drawRadiusExecutive - this Standard&Style is not supported: %d\n", standardStyle);
|
|
}
|
|
|
|
datumLabel->setTransformOriginPoint(datumLabel->boundingRect().center());
|
|
datumLabel->setRotation(toQtDeg(labelAngle));
|
|
|
|
dimLines->setPath(radiusPath);
|
|
}
|
|
|
|
void QGIViewDimension::drawDistance(TechDraw::DrawViewDimension *dimension, ViewProviderDimension *viewProvider) const
|
|
{
|
|
Base::BoundBox2d labelRectangle(fromQtGui(mapRectFromItem(datumLabel, datumLabel->boundingRect())));
|
|
|
|
pointPair linePoints = dimension->getLinearPoints();
|
|
const char *dimensionType = dimension->Type.getValueAsString();
|
|
|
|
double lineAngle;
|
|
if (strcmp(dimensionType, "DistanceX") == 0) {
|
|
lineAngle = 0.0;
|
|
}
|
|
else if (strcmp(dimensionType, "DistanceY") == 0) {
|
|
lineAngle = M_PI_2;
|
|
}
|
|
else {
|
|
lineAngle = (fromQtApp(linePoints.second) - fromQtApp(linePoints.first)).Angle();
|
|
}
|
|
|
|
int standardStyle = viewProvider->StandardAndStyle.getValue();
|
|
int renderExtent = viewProvider->RenderingExtent.getValue();
|
|
bool flipArrows = viewProvider->FlipArrowheads.getValue();
|
|
|
|
|
|
if (dimension->AngleOverride.getValue()) {
|
|
drawDistanceOverride(fromQtApp(linePoints.first), fromQtApp(linePoints.second),
|
|
dimension->LineAngle.getValue() * M_PI / 180.0,
|
|
labelRectangle, standardStyle, renderExtent, flipArrows,
|
|
dimension->ExtensionAngle.getValue() * M_PI / 180.0);
|
|
|
|
} else {
|
|
drawDistanceExecutive(fromQtApp(linePoints.first), fromQtApp(linePoints.second), lineAngle,
|
|
labelRectangle, standardStyle, renderExtent, flipArrows);
|
|
}
|
|
}
|
|
|
|
void QGIViewDimension::drawRadius(TechDraw::DrawViewDimension *dimension, ViewProviderDimension *viewProvider) const
|
|
{
|
|
Base::BoundBox2d labelRectangle(fromQtGui(mapRectFromItem(datumLabel, datumLabel->boundingRect())));
|
|
arcPoints curvePoints = dimension->getArcPoints();
|
|
|
|
double endAngle;
|
|
double startRotation;
|
|
if (curvePoints.isArc) {
|
|
endAngle = (fromQtApp(curvePoints.arcEnds.second) - fromQtApp(curvePoints.center)).Angle();
|
|
startRotation = (fromQtApp(curvePoints.arcEnds.first) - fromQtApp(curvePoints.center)).Angle()
|
|
- endAngle;
|
|
|
|
if (startRotation != 0.0 && ((startRotation > 0.0) != curvePoints.arcCW)) {
|
|
startRotation += curvePoints.arcCW ? +M_2PI : -M_2PI;
|
|
}
|
|
}
|
|
else { // A circle arc covers the whole plane
|
|
endAngle = M_PI;
|
|
startRotation = -M_2PI;
|
|
}
|
|
|
|
drawRadiusExecutive(fromQtApp(curvePoints.center), fromQtApp(curvePoints.midArc),
|
|
curvePoints.radius, endAngle, startRotation, labelRectangle, 0.0,
|
|
viewProvider->StandardAndStyle.getValue(), viewProvider->RenderingExtent.getValue(),
|
|
viewProvider->FlipArrowheads.getValue());
|
|
}
|
|
|
|
void QGIViewDimension::drawDiameter(TechDraw::DrawViewDimension *dimension, ViewProviderDimension *viewProvider) const
|
|
{
|
|
Base::BoundBox2d labelRectangle(fromQtGui(mapRectFromItem(datumLabel, datumLabel->boundingRect())));
|
|
Base::Vector2d labelCenter(labelRectangle.GetCenter());
|
|
|
|
arcPoints curvePoints = dimension->getArcPoints();
|
|
|
|
Base::Vector2d curveCenter(fromQtApp(curvePoints.center));
|
|
double curveRadius = curvePoints.radius;
|
|
|
|
int standardStyle = viewProvider->StandardAndStyle.getValue();
|
|
int renderExtent = viewProvider->RenderingExtent.getValue();
|
|
bool flipArrows = viewProvider->FlipArrowheads.getValue();
|
|
|
|
if (renderExtent == ViewProviderDimension::REND_EXTENT_NORMAL) {
|
|
// Draw diameter as one line crossing center touching two opposite circle points
|
|
QPainterPath diameterPath;
|
|
double labelAngle = 0.0;
|
|
|
|
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
|
|
|| standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING) {
|
|
// The dimensional value text must stay horizontal
|
|
Base::Vector2d jointDirections[2];
|
|
|
|
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING) {
|
|
jointDirections[0] = getIsoRefJointPoint(labelRectangle, false) - curveCenter;
|
|
jointDirections[1] = getIsoRefJointPoint(labelRectangle, true) - curveCenter;
|
|
}
|
|
else {
|
|
jointDirections[0] = getAsmeRefJointPoint(labelRectangle, false) - curveCenter;
|
|
jointDirections[1] = getAsmeRefJointPoint(labelRectangle, true) - curveCenter;
|
|
}
|
|
|
|
// Find the angles of lines from the center
|
|
double lineAngles[2];
|
|
lineAngles[0] = jointDirections[0].Angle();
|
|
lineAngles[1] = jointDirections[1].Angle();
|
|
|
|
Base::Vector2d targetPoints[2];
|
|
targetPoints[0] = curveCenter + Base::Vector2d::FromPolar(curveRadius, lineAngles[0]);
|
|
targetPoints[1] = curveCenter + Base::Vector2d::FromPolar(curveRadius, lineAngles[1]);
|
|
|
|
// Find the positions where the reference line attaches to the dimension line
|
|
double jointPositions[2];
|
|
jointPositions[0] = jointDirections[0].Length() - curveRadius;
|
|
jointPositions[1] = jointDirections[1].Length() - curveRadius;
|
|
|
|
// Select the placement, where the label is not obscured by the leader line
|
|
double strikeFactors[2];
|
|
|
|
std::vector<std::pair<double, bool>> lineMarking;
|
|
constructDimensionLine(targetPoints[0], lineAngles[0], -curveRadius*2.0, jointPositions[0],
|
|
labelRectangle, 2, standardStyle, flipArrows, lineMarking);
|
|
strikeFactors[0] = computeLineStrikeFactor(labelRectangle, targetPoints[0], lineAngles[0], lineMarking);
|
|
|
|
lineMarking.clear();
|
|
constructDimensionLine(targetPoints[1], lineAngles[1], -curveRadius*2.0, jointPositions[1],
|
|
labelRectangle, 2, standardStyle, flipArrows, lineMarking);
|
|
strikeFactors[1] = computeLineStrikeFactor(labelRectangle, targetPoints[1], lineAngles[1], lineMarking);
|
|
|
|
int selected = 0;
|
|
if (compareAngleStraightness(0.0,
|
|
jointPositions[0] > 0.0 ? DrawUtil::angleComposition(lineAngles[0], M_PI) : lineAngles[0],
|
|
jointPositions[1] > 0.0 ? DrawUtil::angleComposition(lineAngles[1], M_PI) : lineAngles[1],
|
|
strikeFactors[0], strikeFactors[1]) > 0) {
|
|
selected = 1;
|
|
}
|
|
|
|
drawDimensionLine(diameterPath, curveCenter + Base::Vector2d::FromPolar(curveRadius, lineAngles[selected]),
|
|
lineAngles[selected], -curveRadius*2.0, jointPositions[selected],
|
|
labelRectangle, 2, standardStyle, flipArrows);
|
|
|
|
Base::Vector2d outsetPoint(standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
|
|
? getIsoRefOutsetPoint(labelRectangle, selected == 1)
|
|
: getAsmeRefOutsetPoint(labelRectangle, selected == 1));
|
|
|
|
diameterPath.moveTo(toQtGui(outsetPoint));
|
|
diameterPath.lineTo(toQtGui(curveCenter + jointDirections[selected]));
|
|
}
|
|
else if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) {
|
|
// We may rotate the label so no reference line is needed
|
|
double lineAngle;
|
|
double devAngle = computeLineAndLabelAngles(curveCenter, labelCenter,
|
|
labelRectangle.Height()*0.5 + getDefaultIsoDimensionLineSpacing(),
|
|
lineAngle, labelAngle);
|
|
|
|
// Correct the label center distance projected on the leader line and subtract radius
|
|
double labelPosition = cos(devAngle)*((labelCenter - curveCenter).Length()) - curveRadius;
|
|
|
|
drawDimensionLine(diameterPath, curveCenter + Base::Vector2d::FromPolar(curveRadius, lineAngle), lineAngle,
|
|
-curveRadius*2.0, labelPosition, labelRectangle, 2, standardStyle, flipArrows);
|
|
}
|
|
else if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
|
|
// Text must remain horizontal, but it may split the leader line
|
|
double lineAngle = (labelCenter - curveCenter).Angle();
|
|
//Base::Vector2d lineDirection(Base::Vector2d::FromPolar(1.0, lineAngle));
|
|
|
|
drawDimensionLine(diameterPath, curveCenter + Base::Vector2d::FromPolar(curveRadius, lineAngle), lineAngle,
|
|
-curveRadius*2.0, (labelCenter - curveCenter).Length() - curveRadius,
|
|
labelRectangle, 2, standardStyle, flipArrows);
|
|
}
|
|
else {
|
|
Base::Console().Error("QGIVD::drawRadius - this Standard&Style is not supported: %d\n", standardStyle);
|
|
}
|
|
|
|
datumLabel->setTransformOriginPoint(datumLabel->boundingRect().center());
|
|
datumLabel->setRotation(toQtDeg(labelAngle));
|
|
|
|
dimLines->setPath(diameterPath);
|
|
}
|
|
else if (renderExtent >= ViewProviderDimension::REND_EXTENT_EXPANDED) {
|
|
double lineAngle = (labelCenter - curveCenter).Angle();
|
|
Base::Vector2d startPoint(curveCenter);
|
|
Base::Vector2d endPoint(curveCenter);
|
|
|
|
if ((lineAngle >= M_PI_4 && lineAngle <= 3.0*M_PI_4) || (lineAngle <= -M_PI_4 && lineAngle >= -3.0*M_PI_4)) {
|
|
// Horizontal dimension line
|
|
startPoint.x -= curveRadius;
|
|
endPoint.x += curveRadius;
|
|
lineAngle = 0.0;
|
|
}
|
|
else { // Vertical dimension line
|
|
startPoint.y -= curveRadius;
|
|
endPoint.y += curveRadius;
|
|
lineAngle = M_PI_2;
|
|
}
|
|
|
|
// lineAngle = DrawUtil::angleComposition((labelCenter - curveCenter).Angle(), +M_PI_2);
|
|
// startPoint = curveCenter - Base::Vector2d::FromPolar(curveRadius, lineAngle);
|
|
// endPoint = curveCenter + Base::Vector2d::FromPolar(curveRadius, lineAngle);
|
|
|
|
drawDistanceExecutive(startPoint, endPoint, lineAngle, labelRectangle,
|
|
standardStyle, ViewProviderDimension::REND_EXTENT_NORMAL, flipArrows);
|
|
}
|
|
else if (renderExtent <= ViewProviderDimension::REND_EXTENT_REDUCED) {
|
|
renderExtent = renderExtent <= ViewProviderDimension::REND_EXTENT_CONFINED
|
|
? ViewProviderDimension::REND_EXTENT_REDUCED
|
|
: ViewProviderDimension::REND_EXTENT_NORMAL;
|
|
|
|
drawRadiusExecutive(curveCenter, Rez::guiX(curvePoints.midArc, true),
|
|
curveRadius, M_PI, -M_2PI, labelRectangle, getDefaultExtensionLineOverhang(),
|
|
standardStyle, renderExtent, flipArrows);
|
|
}
|
|
}
|
|
|
|
void QGIViewDimension::drawAngle(TechDraw::DrawViewDimension *dimension, ViewProviderDimension *viewProvider) const
|
|
{
|
|
QPainterPath anglePath;
|
|
|
|
Base::BoundBox2d labelRectangle(fromQtGui(mapRectFromItem(datumLabel, datumLabel->boundingRect())));
|
|
Base::Vector2d labelCenter(labelRectangle.GetCenter());
|
|
double labelAngle = 0.0;
|
|
|
|
anglePoints anglePoints = dimension->getAnglePoints();
|
|
|
|
Base::Vector2d angleVertex = fromQtApp(anglePoints.vertex);
|
|
Base::Vector2d startPoint = fromQtApp(anglePoints.ends.first);
|
|
Base::Vector2d endPoint = fromQtApp(anglePoints.ends.second);
|
|
|
|
double endAngle = (endPoint - angleVertex).Angle();
|
|
double startAngle = (startPoint - angleVertex).Angle();
|
|
double arcRadius;
|
|
|
|
int standardStyle = viewProvider->StandardAndStyle.getValue();
|
|
int renderExtent = viewProvider->RenderingExtent.getValue();
|
|
bool flipArrows = viewProvider->FlipArrowheads.getValue();
|
|
|
|
int arrowCount = renderExtent >= ViewProviderDimension::REND_EXTENT_NORMAL
|
|
|| renderExtent == ViewProviderDimension::REND_EXTENT_CONFINED
|
|
? 2 : 1;
|
|
|
|
// Inverted dimensions display reflex angles (fi > PI), regular ones oblique angles (fi <= PI/2)
|
|
double startRotation = DrawUtil::angleDifference(startAngle, endAngle, dimension->Inverted.getValue());
|
|
if (arrowCount < 2) {
|
|
// For single arrow, the effective angle span is 0, but still we need to know
|
|
// the angle orientation. Floating point positive/negative zero comes to rescue...
|
|
startRotation = copysign(0.0, startRotation);
|
|
}
|
|
|
|
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
|
|
|| standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING) {
|
|
// The dimensional value text must stay horizontal
|
|
Base::Vector2d jointDirections[2];
|
|
|
|
if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING) {
|
|
jointDirections[0] = getIsoRefJointPoint(labelRectangle, false) - angleVertex;
|
|
jointDirections[1] = getIsoRefJointPoint(labelRectangle, true) - angleVertex;
|
|
}
|
|
else {
|
|
jointDirections[0] = getAsmeRefJointPoint(labelRectangle, false) - angleVertex;
|
|
jointDirections[1] = getAsmeRefJointPoint(labelRectangle, true) - angleVertex;
|
|
}
|
|
|
|
// Get radiuses of the angle dimension arcs
|
|
double arcRadii[2];
|
|
arcRadii[0] = jointDirections[0].Length();
|
|
arcRadii[1] = jointDirections[1].Length();
|
|
|
|
// Compute the reference line joint angles
|
|
double jointAngles[2];
|
|
jointAngles[0] = jointDirections[0].Angle();
|
|
jointAngles[1] = jointDirections[1].Angle();
|
|
|
|
double handednessFactor = normalizeStartRotation(startRotation);
|
|
double jointRotations[2];
|
|
jointRotations[0] = handednessFactor*(jointAngles[0] - endAngle);
|
|
jointRotations[1] = handednessFactor*(jointAngles[1] - endAngle);
|
|
|
|
// Compare the offset with half of the rest of 2PI minus the angle and eventually fix the values
|
|
if (fabs(jointRotations[0] - startRotation*0.5) > M_PI) {
|
|
jointRotations[0] += jointRotations[0] < 0.0 ? +M_2PI : -M_2PI;
|
|
}
|
|
if (fabs(jointRotations[1] - startRotation*0.5) > M_PI) {
|
|
jointRotations[1] += jointRotations[1] < 0.0 ? +M_2PI : -M_2PI;
|
|
}
|
|
|
|
// Compute the strike factors so we can choose the placement where value is not obscured by dimensional arc
|
|
double strikeFactors[2];
|
|
|
|
std::vector<std::pair<double, bool>> arcMarking;
|
|
constructDimensionArc(angleVertex, arcRadii[0], endAngle, startRotation, handednessFactor, jointRotations[0],
|
|
labelRectangle, arrowCount, standardStyle, flipArrows, arcMarking);
|
|
strikeFactors[0] = computeArcStrikeFactor(labelRectangle, angleVertex, arcRadii[0], arcMarking);
|
|
|
|
arcMarking.clear();
|
|
constructDimensionArc(angleVertex, arcRadii[1], endAngle, startRotation, handednessFactor, jointRotations[1],
|
|
labelRectangle, arrowCount, standardStyle, flipArrows, arcMarking);
|
|
strikeFactors[1] = computeArcStrikeFactor(labelRectangle, angleVertex, arcRadii[1], arcMarking);
|
|
|
|
int selected = 0;
|
|
if (compareAngleStraightness(0.0,
|
|
DrawUtil::angleComposition(jointAngles[0],
|
|
handednessFactor*jointRotations[0] > 0.0 ? -M_PI_2 : +M_PI_2),
|
|
DrawUtil::angleComposition(jointAngles[1],
|
|
handednessFactor*jointRotations[1] > 0.0 ? -M_PI_2 : +M_PI_2),
|
|
strikeFactors[0], strikeFactors[1]) > 0) {
|
|
selected = 1;
|
|
}
|
|
|
|
arcRadius = arcRadii[selected];
|
|
startRotation = copysign(startRotation, -handednessFactor);
|
|
|
|
drawDimensionArc(anglePath, angleVertex, arcRadius, endAngle, startRotation,
|
|
jointAngles[selected], labelRectangle, arrowCount, standardStyle, flipArrows);
|
|
|
|
Base::Vector2d outsetPoint(standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING
|
|
? getIsoRefOutsetPoint(labelRectangle, selected == 1)
|
|
: getAsmeRefOutsetPoint(labelRectangle, selected == 1));
|
|
|
|
anglePath.moveTo(toQtGui(outsetPoint));
|
|
anglePath.lineTo(toQtGui(angleVertex + jointDirections[selected]));
|
|
}
|
|
else if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) {
|
|
// We may rotate the label so no leader and reference lines are needed
|
|
Base::Vector2d labelDirection(labelCenter - angleVertex);
|
|
double radiusAngle = labelDirection.Angle();
|
|
|
|
labelAngle = DrawUtil::angleComposition(radiusAngle, M_PI_2);
|
|
double placementFactor = getIsoStandardLinePlacement(labelAngle);
|
|
labelAngle = placementFactor > 0.0 ? DrawUtil::angleComposition(labelAngle, M_PI) : labelAngle;
|
|
|
|
arcRadius = labelDirection.Length()
|
|
- placementFactor*(labelRectangle.Height()*0.5 + getDefaultIsoDimensionLineSpacing());
|
|
if (arcRadius < 0.0) {
|
|
arcRadius = labelDirection.Length();
|
|
}
|
|
|
|
drawDimensionArc(anglePath, angleVertex, arcRadius, endAngle, startRotation, radiusAngle,
|
|
labelRectangle, arrowCount, standardStyle, flipArrows);
|
|
}
|
|
else if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
|
|
// Text must remain horizontal, but it may split the leader line
|
|
Base::Vector2d labelDirection(labelCenter - angleVertex);
|
|
arcRadius = labelDirection.Length();
|
|
|
|
drawDimensionArc(anglePath, angleVertex, arcRadius, endAngle, startRotation, labelDirection.Angle(),
|
|
labelRectangle, arrowCount, standardStyle, flipArrows);
|
|
}
|
|
else {
|
|
Base::Console().Error("QGIVD::drawAngle - this Standard&Style is not supported: %d\n", standardStyle);
|
|
arrowCount = 0;
|
|
}
|
|
|
|
if (arrowCount > 0 && renderExtent >= ViewProviderDimension::REND_EXTENT_REDUCED) {
|
|
double gapSize = 0.0;
|
|
if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING
|
|
|| standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) {
|
|
gapSize = getDefaultAsmeExtensionLineGap();
|
|
}
|
|
|
|
Base::Vector2d extensionOrigin;
|
|
Base::Vector2d extensionTarget(computeExtensionLinePoints(endPoint,
|
|
angleVertex + Base::Vector2d::FromPolar(arcRadius, endAngle), endAngle,
|
|
getDefaultExtensionLineOverhang(), gapSize, extensionOrigin));
|
|
anglePath.moveTo(toQtGui(extensionOrigin));
|
|
anglePath.lineTo(toQtGui(extensionTarget));
|
|
|
|
if (arrowCount > 1) {
|
|
extensionTarget = computeExtensionLinePoints(startPoint,
|
|
angleVertex + Base::Vector2d::FromPolar(arcRadius, startAngle),
|
|
startAngle, getDefaultExtensionLineOverhang(),
|
|
gapSize, extensionOrigin);
|
|
anglePath.moveTo(toQtGui(extensionOrigin));
|
|
anglePath.lineTo(toQtGui(extensionTarget));
|
|
}
|
|
}
|
|
|
|
datumLabel->setTransformOriginPoint(datumLabel->boundingRect().center());
|
|
datumLabel->setRotation(toQtDeg(labelAngle));
|
|
|
|
dimLines->setPath(anglePath);
|
|
}
|
|
|
|
QColor QGIViewDimension::prefNormalColor()
|
|
{
|
|
m_colNormal = PreferencesGui::dimQColor();
|
|
|
|
// auto dim( dynamic_cast<TechDraw::DrawViewDimension*>(getViewObject()) );
|
|
TechDraw::DrawViewDimension* dim = nullptr;
|
|
TechDraw::DrawView* dv = getViewObject();
|
|
if (dv != nullptr) {
|
|
dim = dynamic_cast<TechDraw::DrawViewDimension*>(dv);
|
|
if( dim == nullptr ) {
|
|
return m_colNormal;
|
|
}
|
|
} else {
|
|
return m_colNormal;
|
|
}
|
|
|
|
ViewProviderDimension* vpDim = nullptr;
|
|
Gui::ViewProvider* vp = getViewProvider(dim);
|
|
if ( vp != nullptr ) {
|
|
vpDim = dynamic_cast<ViewProviderDimension*>(vp);
|
|
if (vpDim == nullptr) {
|
|
return m_colNormal;
|
|
}
|
|
} else {
|
|
return m_colNormal;
|
|
}
|
|
|
|
App::Color fcColor = vpDim->Color.getValue();
|
|
m_colNormal = fcColor.asValue<QColor>();
|
|
return m_colNormal;
|
|
}
|
|
|
|
//! find the closest isometric axis given an ortho vector
|
|
Base::Vector3d QGIViewDimension::findIsoDir(Base::Vector3d ortho) const
|
|
{
|
|
std::vector<Base::Vector3d> isoDirs = { Base::Vector3d(0.866,0.5,0.0), //iso X
|
|
Base::Vector3d(-0.866,-0.5,0.0), //iso -X
|
|
Base::Vector3d(-0.866,0.5,0.0), //iso -Y?
|
|
Base::Vector3d(0.866,-0.5,0.0), //iso +Y?
|
|
Base::Vector3d(0.0,-1.0,0.0), //iso -Z
|
|
Base::Vector3d(0.0,1.0,0.0) }; //iso Z
|
|
std::vector<double> angles;
|
|
for (auto& iso: isoDirs) {
|
|
angles.push_back(ortho.GetAngle(iso));
|
|
}
|
|
int idx = 0;
|
|
double min = angles[0];
|
|
for (int i = 1; i < 6; i++) {
|
|
if (angles[i] < min) {
|
|
idx = i;
|
|
min = angles[i];
|
|
}
|
|
}
|
|
return isoDirs[idx];
|
|
}
|
|
|
|
//! find the iso extension direction corresponding to an iso dist direction
|
|
Base::Vector3d QGIViewDimension::findIsoExt(Base::Vector3d dir) const
|
|
{
|
|
Base::Vector3d dirExt(1,0,0);
|
|
Base::Vector3d isoX(0.866,0.5,0.0); //iso X
|
|
Base::Vector3d isoXr(-0.866,-0.5,0.0); //iso -X
|
|
Base::Vector3d isoY(-0.866,0.5,0.0); //iso -Y?
|
|
Base::Vector3d isoYr(0.866,-0.5,0.0); //iso +Y?
|
|
Base::Vector3d isoZ(0.0,1.0,0.0); //iso Z
|
|
Base::Vector3d isoZr(0.0,-1.0,0.0); //iso -Z
|
|
if (dir.IsEqual(isoX, FLT_EPSILON)) {
|
|
dirExt = isoY;
|
|
} else if (dir.IsEqual(-isoX, FLT_EPSILON)) {
|
|
dirExt = -isoY;
|
|
} else if (dir.IsEqual(isoY, FLT_EPSILON)) {
|
|
dirExt = isoZ;
|
|
} else if (dir.IsEqual(-isoY, FLT_EPSILON)) {
|
|
dirExt = -isoZ;
|
|
} else if (dir.IsEqual(isoZ, FLT_EPSILON)) {
|
|
dirExt = isoX;
|
|
} else if (dir.IsEqual(-isoZ, FLT_EPSILON)) {
|
|
dirExt = -isoX;
|
|
} else { //tarfu
|
|
Base::Console().Message("QGIVD::findIsoExt - %s - input is not iso axis\n", getViewObject()->getNameInDocument());
|
|
}
|
|
|
|
return dirExt;
|
|
}
|
|
|
|
void QGIViewDimension::onPrettyChanged(int state)
|
|
{
|
|
// Base::Console().Message("QGIVD::onPrettyChange(%d)\n", state);
|
|
if (state == NORMAL) {
|
|
setPrettyNormal();
|
|
} else if (state == PRE) {
|
|
setPrettyPre();
|
|
} else { //if state = SEL
|
|
setPrettySel();
|
|
}
|
|
}
|
|
|
|
void QGIViewDimension::setPrettyPre(void)
|
|
{
|
|
aHead1->setPrettyPre();
|
|
aHead2->setPrettyPre();
|
|
dimLines->setPrettyPre();
|
|
}
|
|
|
|
void QGIViewDimension::setPrettySel(void)
|
|
{
|
|
aHead1->setPrettySel();
|
|
aHead2->setPrettySel();
|
|
dimLines->setPrettySel();
|
|
}
|
|
|
|
void QGIViewDimension::setPrettyNormal(void)
|
|
{
|
|
aHead1->setPrettyNormal();
|
|
aHead2->setPrettyNormal();
|
|
dimLines->setPrettyNormal();
|
|
}
|
|
|
|
void QGIViewDimension::drawBorder(void)
|
|
{
|
|
//Dimensions have no border!
|
|
// Base::Console().Message("TRACE - QGIViewDimension::drawBorder - doing nothing!\n");
|
|
}
|
|
|
|
double QGIViewDimension::getDefaultExtensionLineOverhang() const
|
|
{
|
|
// 8x Line Width according to ISO 129-1 Standard section 5.4, not specified by ASME Y14.5M
|
|
return Rez::appX(m_lineWidth*8.0);
|
|
}
|
|
|
|
double QGIViewDimension::getDefaultArrowTailLength() const
|
|
{
|
|
// Arrow length shall be equal to font height and both ISO and ASME seem
|
|
// to have arrow tail twice the arrow length, so let's make it twice arrow size
|
|
return QGIArrow::getPrefArrowSize()*2.0;
|
|
}
|
|
|
|
double QGIViewDimension::getDefaultIsoDimensionLineSpacing() const
|
|
{
|
|
// Not specified directly, but seems to be 2x Line Width according to ISO 129-1 Annex A
|
|
return Rez::appX(m_lineWidth*2.0);
|
|
}
|
|
|
|
double QGIViewDimension::getDefaultIsoReferenceLineOverhang() const
|
|
{
|
|
// Not specified directly but seems to be exactly Line Width according to ISO 129-1 Annex A
|
|
return Rez::appX(m_lineWidth*1.0);
|
|
}
|
|
|
|
double QGIViewDimension::getDefaultAsmeHorizontalLeaderLength() const
|
|
{
|
|
// Not specified by ASME Y14.5M, this is a best guess
|
|
return Rez::appX(m_lineWidth*12);
|
|
}
|
|
|
|
double QGIViewDimension::getDefaultAsmeExtensionLineGap() const
|
|
{
|
|
// Not specified by ASME Y14.5M, this is a best guess
|
|
return Rez::appX(m_lineWidth*6.0);
|
|
}
|
|
|
|
//frame, border, caption are never shown in QGIVD, so shouldn't be in bRect
|
|
QRectF QGIViewDimension::boundingRect() const
|
|
{
|
|
QRectF labelRect = mapFromItem(datumLabel, datumLabel->boundingRect()).boundingRect();
|
|
QRectF linesRect = mapFromItem(dimLines, dimLines->boundingRect()).boundingRect();
|
|
QRectF aHead1Rect = mapFromItem(aHead1, aHead1->boundingRect()).boundingRect();
|
|
QRectF aHead2Rect = mapFromItem(aHead2, aHead2->boundingRect()).boundingRect();
|
|
QRectF result(labelRect);
|
|
result = result.united(linesRect);
|
|
result = result.united(aHead1Rect);
|
|
result = result.united(aHead2Rect);
|
|
return result;
|
|
}
|
|
|
|
void QGIViewDimension::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) {
|
|
QStyleOptionGraphicsItem myOption(*option);
|
|
myOption.state &= ~QStyle::State_Selected;
|
|
|
|
QPaintDevice* hw = painter->device();
|
|
QSvgGenerator* svg = dynamic_cast<QSvgGenerator*>(hw);
|
|
setPens();
|
|
//double arrowSaveWidth = aHead1->getWidth();
|
|
if (svg) {
|
|
setSvgPens();
|
|
} else {
|
|
setPens();
|
|
}
|
|
|
|
// painter->setPen(Qt::red);
|
|
// painter->drawRect(boundingRect()); //good for debugging
|
|
|
|
// QGIView::paint (painter, &myOption, widget);
|
|
QGraphicsItemGroup::paint(painter, &myOption, widget);
|
|
setPens();
|
|
}
|
|
|
|
void QGIViewDimension::setSvgPens(void)
|
|
{
|
|
double svgLineFactor = 3.0; //magic number. should be a setting somewhere.
|
|
dimLines->setWidth(m_lineWidth/svgLineFactor);
|
|
aHead1->setWidth(aHead1->getWidth()/svgLineFactor);
|
|
aHead2->setWidth(aHead2->getWidth()/svgLineFactor);
|
|
}
|
|
|
|
void QGIViewDimension::setPens(void)
|
|
{
|
|
dimLines->setWidth(m_lineWidth);
|
|
aHead1->setWidth(m_lineWidth);
|
|
aHead2->setWidth(m_lineWidth);
|
|
}
|
|
|
|
double QGIViewDimension::toDeg(double a)
|
|
{
|
|
return a*180/M_PI;
|
|
}
|
|
|
|
double QGIViewDimension::toQtRad(double a)
|
|
{
|
|
return -a;
|
|
}
|
|
|
|
double QGIViewDimension::toQtDeg(double a)
|
|
{
|
|
return -a*180.0/M_PI;
|
|
}
|
|
|
|
void QGIViewDimension::makeMarkC(double x, double y, QColor c) const
|
|
{
|
|
QGIVertex* vItem = new QGIVertex(-1);
|
|
vItem->setParentItem(const_cast<QGIViewDimension*>(this));
|
|
vItem->setPos(x,y);
|
|
vItem->setWidth(2.0);
|
|
vItem->setRadius(20.0);
|
|
vItem->setNormalColor(c);
|
|
vItem->setFillColor(c);
|
|
vItem->setPrettyNormal();
|
|
vItem->setZValue(ZVALUE::VERTEX);
|
|
}
|
|
|
|
|
|
|
|
#include <Mod/TechDraw/Gui/moc_QGIViewDimension.cpp>
|