1
/***************************************************************************
2
* Copyright (c) 2013 Luke Parry <l.parry@warwick.ac.uk> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
27
#include <QPainterPath>
30
#endif// #ifndef _PreComp_
32
#include <App/Application.h>
33
#include <App/Document.h>
34
#include <Base/Console.h>
35
#include <Base/Parameter.h>
36
#include <Base/Vector3D.h>
37
#include <Gui/Selection.h>
38
#include <Mod/TechDraw/App/CenterLine.h>
39
#include <Mod/TechDraw/App/Cosmetic.h>
40
#include <Mod/TechDraw/App/DrawComplexSection.h>
41
#include <Mod/TechDraw/App/DrawGeomHatch.h>
42
#include <Mod/TechDraw/App/DrawHatch.h>
43
#include <Mod/TechDraw/App/DrawUtil.h>
44
#include <Mod/TechDraw/App/DrawViewDetail.h>
45
#include <Mod/TechDraw/App/DrawViewPart.h>
46
#include <Mod/TechDraw/App/DrawViewSection.h>
47
#include <Mod/TechDraw/App/Geometry.h>
49
#include "DrawGuiUtil.h"
50
#include "MDIViewPage.h"
51
#include "PreferencesGui.h"
53
#include "QGICenterLine.h"
56
#include "QGIHighlight.h"
57
#include "QGIMatting.h"
58
#include "QGISectionLine.h"
60
#include "QGIViewPart.h"
62
#include "ViewProviderGeomHatch.h"
63
#include "ViewProviderHatch.h"
64
#include "ViewProviderViewPart.h"
66
#include "PathBuilder.h"
68
using namespace TechDraw;
69
using namespace TechDrawGui;
77
const float lineScaleFactor = Rez::guiX(1.);// temp fiddle for devel
79
QGIViewPart::QGIViewPart()
81
setCacheMode(QGraphicsItem::NoCache);
82
setHandlesChildEvents(false);
83
setAcceptHoverEvents(true);
84
setFlag(QGraphicsItem::ItemIsSelectable, true);
85
setFlag(QGraphicsItem::ItemIsMovable, true);
86
setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true);
87
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
88
setFlag(QGraphicsItem::ItemIsFocusable, true);
91
m_pathBuilder = new PathBuilder(this);
92
m_dashedLineGenerator = new LineGenerator();
95
QGIViewPart::~QGIViewPart()
99
delete m_dashedLineGenerator;
102
QVariant QGIViewPart::itemChange(GraphicsItemChange change, const QVariant& value)
104
if (change == ItemSelectedHasChanged && scene()) {
105
//There's nothing special for QGIVP to do when selection changes!
107
else if (change == ItemSceneChange && scene()) {
110
return QGIView::itemChange(change, value);
113
bool QGIViewPart::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
115
// Base::Console().Message("QGIVP::sceneEventFilter - event: %d watchedtype: %d\n",
116
// event->type(), watched->type() - QGraphicsItem::UserType);
117
if (event->type() == QEvent::ShortcutOverride) {
118
// if we accept this event, we should get a regular keystroke event next
119
// which will be processed by QGVPage/QGVNavStyle keypress logic, but not forwarded to
121
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
122
if (keyEvent->key() == Qt::Key_Delete) {
123
bool success = removeSelectedCosmetic();
132
return QGraphicsItem::sceneEventFilter(watched, event);
135
//! called when a DEL shortcut event is received. If a cosmetic edge or vertex is
136
//! selected, remove it from the view.
137
bool QGIViewPart::removeSelectedCosmetic() const
139
// Base::Console().Message("QGIVP::removeSelectedCosmetic()\n");
140
char* defaultDocument{nullptr};
141
std::vector<Gui::SelectionObject> selectionAll = Gui::Selection().getSelectionEx(
142
defaultDocument, TechDraw::DrawViewPart::getClassTypeId(), Gui::ResolveMode::NoResolve);
143
if (selectionAll.empty()) {
146
Gui::SelectionObject firstSelection = selectionAll.front();
147
App::DocumentObject* firstObject = selectionAll.front().getObject();
148
std::vector<std::string> subElements = selectionAll.front().getSubNames();
149
if (subElements.empty()) {
152
auto dvp = static_cast<TechDraw::DrawViewPart*>(firstObject);
153
auto subelement = subElements.front();
154
std::string geomName = DU::getGeomTypeFromName(subelement);
155
int index = DU::getIndexFromName(subelement);
156
if (geomName == "Edge") {
157
TechDraw::BaseGeomPtr base = dvp->getGeomByIndex(index);
158
if (!base || base->getCosmeticTag().empty()) {
161
if (base->source() == COSMETICEDGE) {
162
dvp->removeCosmeticEdge(base->getCosmeticTag());
163
dvp->refreshCEGeoms();
164
} else if (base->source() == CENTERLINE) {
165
dvp->removeCenterLine(base->getCosmeticTag());
166
dvp->refreshCLGeoms();
168
Base::Console().Message("QGIVP::removeSelectedCosmetic - not a CE or a CL\n");
171
} else if (geomName == "Vertex") {
172
VertexPtr vert = dvp->getProjVertexByIndex(index);
173
if (!vert || vert->getCosmeticTag().empty() ) {
176
dvp->removeCosmeticVertex(vert->getCosmeticTag());
177
dvp->refreshCVGeoms();
185
void QGIViewPart::tidy()
187
//Delete any leftover items
188
for (QList<QGraphicsItem*>::iterator it = deleteItems.begin(); it != deleteItems.end(); ++it) {
194
void QGIViewPart::setViewPartFeature(TechDraw::DrawViewPart* obj)
199
setViewFeature(static_cast<TechDraw::DrawView*>(obj));
202
QPainterPath QGIViewPart::drawPainterPath(TechDraw::BaseGeomPtr baseGeom) const
204
double rot = getViewObject()->Rotation.getValue();
205
return m_pathBuilder->geomToPainterPath(baseGeom, rot);
208
void QGIViewPart::updateView(bool update)
210
// Base::Console().Message("QGIVP::updateView() - %s\n", getViewObject()->getNameInDocument());
211
auto viewPart(dynamic_cast<TechDraw::DrawViewPart*>(getViewObject()));
214
auto vp = static_cast<ViewProviderViewPart*>(getViewProvider(getViewObject()));
220
QGIView::updateView(update);
223
void QGIViewPart::draw()
225
auto viewPart(dynamic_cast<TechDraw::DrawViewPart*>(getViewObject()));
230
auto doc = viewPart->getDocument();
231
if (!doc || doc->testStatus(App::Document::Status::Restoring)) {
232
// if the document is still restoring, we may not have all the information
233
// we need to draw the source objects, so we wait until restore is finished.
234
// Base::Console().Message("QGIVP::draw - document is restoring, do not draw\n");
245
drawCenterLines(true);//have to draw centerlines after border to get size correct.
246
drawAllSectionLines();//same for section lines
249
void QGIViewPart::drawViewPart()
251
auto viewPart(dynamic_cast<TechDraw::DrawViewPart*>(getViewObject()));
254
// Base::Console().Message("QGIVP::DVP() - %s / %s\n", viewPart->getNameInDocument(), viewPart->Label.getValue());
255
if (!viewPart->hasGeometry()) {
256
removePrimitives();//clean the slate
261
auto vp = static_cast<ViewProviderViewPart*>(getViewProvider(getViewObject()));
265
prepareGeometryChange();
266
removePrimitives();//clean the slate
269
if (viewPart->handleFaces() && !viewPart->CoarseView.getValue()) {
278
void QGIViewPart::drawAllFaces(void)
280
// dvp already validated
281
auto dvp(static_cast<TechDraw::DrawViewPart*>(getViewObject()));
284
auto vpp = dynamic_cast<ViewProviderViewPart *>(getViewProvider(getViewObject()));
286
faceColor = vpp->FaceColor.getValue().asValue<QColor>();
287
faceColor.setAlpha((100 - vpp->FaceTransparency.getValue())*255/100);
290
std::vector<TechDraw::DrawHatch*> regularHatches = dvp->getHatches();
291
std::vector<TechDraw::DrawGeomHatch*> geomHatches = dvp->getGeomHatches();
292
const std::vector<TechDraw::FacePtr>& faceGeoms = dvp->getFaceGeometry();
294
for (auto& face : faceGeoms) {
295
QGIFace* newFace = drawFace(face, iFace);
296
if (faceColor.isValid()) {
297
newFace->setFillColor(faceColor);
298
newFace->setFillMode(faceColor.alpha() ? QGIFace::PlainFill : QGIFace::NoFill);
301
TechDraw::DrawHatch* fHatch = faceIsHatched(iFace, regularHatches);
302
TechDraw::DrawGeomHatch* fGeom = faceIsGeomHatched(iFace, geomHatches);
304
// geometric hatch (from PAT hatch specification)
305
newFace->isHatched(true);
306
newFace->setFillMode(QGIFace::GeomHatchFill);
307
std::vector<LineSet> lineSets = fGeom->getTrimmedLines(iFace);
308
if (!lineSets.empty()) {
309
// this face has geometric hatch lines
310
newFace->clearLineSets();
311
for (auto& ls : lineSets) {
312
newFace->addLineSet(ls);
315
double hatchScale = fGeom->ScalePattern.getValue();
316
if (hatchScale > 0.0) {
317
newFace->setHatchScale(fGeom->ScalePattern.getValue());
319
newFace->setHatchRotation(fGeom->PatternRotation.getValue());
320
newFace->setHatchOffset(fGeom->PatternOffset.getValue());
321
newFace->setHatchFile(fGeom->PatIncluded.getValue());
322
Gui::ViewProvider* gvp = QGIView::getViewProvider(fGeom);
323
ViewProviderGeomHatch* geomVp = dynamic_cast<ViewProviderGeomHatch*>(gvp);
325
newFace->setHatchColor(geomVp->ColorPattern.getValue());
326
newFace->setLineWeight(geomVp->WeightPattern.getValue());
329
// svg or bitmap hatch
330
newFace->isHatched(true);
331
if (!fHatch->SvgIncluded.isEmpty()) {
332
newFace->setHatchFile(fHatch->SvgIncluded.getValue());
334
if (fHatch->isSvgHatch()) {
336
newFace->setFillMode(QGIFace::SvgFill);
337
newFace->hideSvg(false);
340
newFace->setFillMode(QGIFace::BitmapFill);
343
// get the properties from the hatch viewprovider
344
Gui::ViewProvider* gvp = QGIView::getViewProvider(fHatch);
345
ViewProviderHatch* hatchVp = dynamic_cast<ViewProviderHatch*>(gvp);
347
if (hatchVp->HatchScale.getValue() > 0.0) {
348
newFace->setHatchScale(hatchVp->HatchScale.getValue());
350
newFace->setHatchColor(hatchVp->HatchColor.getValue());
351
newFace->setHatchRotation(hatchVp->HatchRotation.getValue());
352
newFace->setHatchOffset(hatchVp->HatchOffset.getValue());
356
newFace->setDrawEdges(prefFaceEdges());
357
newFace->setZValue(ZVALUE::FACE);
358
newFace->setPrettyNormal();
364
void QGIViewPart::drawAllEdges()
366
// dvp and vp already validated
367
auto dvp(static_cast<TechDraw::DrawViewPart*>(getViewObject()));
368
auto vp = static_cast<ViewProviderViewPart*>(getViewProvider(getViewObject()));
370
const TechDraw::BaseGeomPtrVector& geoms = dvp->getEdgeGeometry();
371
TechDraw::BaseGeomPtrVector::const_iterator itGeom = geoms.begin();
373
for (int iEdge = 0; itGeom != geoms.end(); itGeom++, iEdge++) {
374
bool showItem = true;
375
if (!showThisEdge(*itGeom)) {
379
item = new QGIEdge(iEdge);
380
addToGroup(item); //item is created at scene(0, 0), not group(0, 0)
381
item->setPath(drawPainterPath(*itGeom));
382
item->setSource((*itGeom)->source());
384
item->setNormalColor(PreferencesGui::getAccessibleQColor(PreferencesGui::normalQColor()));
385
if ((*itGeom)->getCosmetic()) {
386
// cosmetic edge - format appropriately
387
int source = (*itGeom)->source();
388
if (source == COSMETICEDGE) {
389
std::string cTag = (*itGeom)->getCosmeticTag();
390
showItem = formatGeomFromCosmetic(cTag, item);
392
else if (source == CENTERLINE) {
393
std::string cTag = (*itGeom)->getCosmeticTag();
394
showItem = formatGeomFromCenterLine(cTag, item);
397
Base::Console().Message("QGIVP::drawVP - cosmetic edge: %d is confused - source: %d\n",
401
// geometry edge - apply format if applicable
402
TechDraw::GeomFormat* gf = dvp->getGeomFormatBySelection(iEdge);
404
App::Color color = Preferences::getAccessibleColor(gf->m_format.m_color);
405
item->setNormalColor(color.asValue<QColor>());
406
int lineNumber = gf->m_format.getLineNumber();
407
int qtStyle = gf->m_format.m_style;
408
item->setLinePen(m_dashedLineGenerator->getBestPen(lineNumber, (Qt::PenStyle)qtStyle,
409
gf->m_format.m_weight));
410
// but we need to actually draw the lines in QGScene coords (0.1 mm).
411
item->setWidth(Rez::guiX(gf->m_format.m_weight));
412
showItem = gf->m_format.m_visible;
414
// unformatted line, draw as continuous line
415
item->setLinePen(m_dashedLineGenerator->getLinePen(1, vp->LineWidth.getValue()));
416
item->setWidth(Rez::guiX(vp->LineWidth.getValue()));
420
if (!(*itGeom)->getHlrVisible()) {
421
item->setLinePen(m_dashedLineGenerator->getLinePen(Preferences::HiddenLineStyle(),
422
vp->LineWidth.getValue()));
423
item->setWidth(Rez::guiX(vp->HiddenWidth.getValue())); //thin
424
item->setZValue(ZVALUE::HIDEDGE);
427
if ((*itGeom)->getClassOfEdge() == ecUVISO) {
428
// we don't have a style option for iso-parametric lines so draw continuous
429
item->setLinePen(m_dashedLineGenerator->getLinePen(1, vp->IsoWidth.getValue()));
430
item->setWidth(Rez::guiX(vp->IsoWidth.getValue())); //graphic
433
item->setPos(0.0, 0.0);//now at group(0, 0)
434
item->setZValue(ZVALUE::EDGE);
435
item->setPrettyNormal();
437
if (!vp->ShowAllEdges.getValue() && !showItem) {
438
//view level "show" status && individual edge "show" status
443
// QPainterPath edgePath=drawPainterPath(*itGeom);
444
// std::stringstream edgeId;
445
// edgeId << "QGIVP.edgePath" << i;
446
// dumpPath(edgeId.str().c_str(), edgePath);
450
void QGIViewPart::drawAllVertexes()
452
// dvp and vp already validated
453
auto dvp(static_cast<TechDraw::DrawViewPart*>(getViewObject()));
454
auto vp(static_cast<ViewProviderViewPart*>(getViewProvider(getViewObject())));
456
float lineWidth = vp->LineWidth.getValue() * lineScaleFactor; //thick
457
double vertexScaleFactor = Preferences::getPreferenceGroup("General")->GetFloat("VertexScale", 3.0);
458
QColor vertexColor = PreferencesGui::getAccessibleQColor(PreferencesGui::vertexQColor());
460
const std::vector<TechDraw::VertexPtr>& verts = dvp->getVertexGeometry();
461
std::vector<TechDraw::VertexPtr>::const_iterator vert = verts.begin();
462
for (int i = 0; vert != verts.end(); ++vert, i++) {
463
if ((*vert)->isCenter()) {
464
if (showCenterMarks()) {
465
QGICMark* cmItem = new QGICMark(i);
467
cmItem->setPos(Rez::guiX((*vert)->x()), Rez::guiX((*vert)->y()));
468
cmItem->setThick(0.5 * lineWidth);//need minimum?
469
cmItem->setSize(lineWidth * vertexScaleFactor * vp->CenterScale.getValue());
470
cmItem->setPrettyNormal();
471
cmItem->setZValue(ZVALUE::VERTEX);
475
if (showVertices()) {
476
QGIVertex* item = new QGIVertex(i);
478
item->setPos(Rez::guiX((*vert)->x()), Rez::guiX((*vert)->y()));
479
item->setNormalColor(vertexColor);
480
item->setFillColor(vertexColor);
481
item->setRadius(lineWidth * vertexScaleFactor);
482
item->setPrettyNormal();
483
item->setZValue(ZVALUE::VERTEX);
489
bool QGIViewPart::showThisEdge(BaseGeomPtr geom)
491
// dvp and vp already validated
492
auto dvp(static_cast<TechDraw::DrawViewPart*>(getViewObject()));
494
if (geom->getHlrVisible()) {
495
if ((geom->getClassOfEdge() == ecHARD) || (geom->getClassOfEdge() == ecOUTLINE)
496
|| ((geom->getClassOfEdge() == ecSMOOTH) && dvp->SmoothVisible.getValue())
497
|| ((geom->getClassOfEdge() == ecSEAM) && dvp->SeamVisible.getValue())
498
|| ((geom->getClassOfEdge() == ecUVISO) && dvp->IsoVisible.getValue())) {
502
if (((geom->getClassOfEdge() == ecHARD) && (dvp->HardHidden.getValue()))
503
|| ((geom->getClassOfEdge() == ecOUTLINE) && (dvp->HardHidden.getValue()))
504
|| ((geom->getClassOfEdge() == ecSMOOTH) && (dvp->SmoothHidden.getValue()))
505
|| ((geom->getClassOfEdge() == ecSEAM) && (dvp->SeamHidden.getValue()))
506
|| ((geom->getClassOfEdge() == ecUVISO) && (dvp->IsoHidden.getValue()))) {
514
// returns true if vertex dots should be shown
515
bool QGIViewPart::showVertices()
517
// dvp and vp already validated
518
auto dvp(static_cast<TechDraw::DrawViewPart*>(getViewObject()));
520
if (dvp->CoarseView.getValue()) {
521
// never show vertices in CoarseView
524
if (!getFrameState()) {
525
// frames are off, don't show vertices
533
// returns true if arc center marks should be shown
534
bool QGIViewPart::showCenterMarks()
536
// dvp and vp already validated
537
auto dvp(static_cast<TechDraw::DrawViewPart*>(getViewObject()));
538
auto vp(static_cast<ViewProviderViewPart*>(getViewProvider(dvp)));
540
if (!vp->ArcCenterMarks.getValue()) {
541
// no center marks if view property is false
545
if (getFrameState()) {
546
// frames are on and view property is true
550
if (prefPrintCenters()) {
551
// frames are off, view property is true and Print Center Marks is true
559
bool QGIViewPart::formatGeomFromCosmetic(std::string cTag, QGIEdge* item)
561
// Base::Console().Message("QGIVP::formatGeomFromCosmetic(%s)\n", cTag.c_str());
563
auto partFeat(dynamic_cast<TechDraw::DrawViewPart*>(getViewObject()));
564
TechDraw::CosmeticEdge* ce = partFeat ? partFeat->getCosmeticEdge(cTag) : nullptr;
566
App::Color color = Preferences::getAccessibleColor(ce->m_format.m_color);
567
item->setNormalColor(color.asValue<QColor>());
568
item->setLinePen(m_dashedLineGenerator->getBestPen(ce->m_format.getLineNumber(),
569
(Qt::PenStyle)ce->m_format.m_style,
570
ce->m_format.m_weight));
571
item->setWidth(Rez::guiX(ce->m_format.m_weight));
572
result = ce->m_format.m_visible;
578
bool QGIViewPart::formatGeomFromCenterLine(std::string cTag, QGIEdge* item)
580
// Base::Console().Message("QGIVP::formatGeomFromCenterLine()\n");
582
auto partFeat(dynamic_cast<TechDraw::DrawViewPart*>(getViewObject()));
583
TechDraw::CenterLine* cl = partFeat ? partFeat->getCenterLine(cTag) : nullptr;
585
App::Color color = Preferences::getAccessibleColor(cl->m_format.m_color);
586
item->setNormalColor(color.asValue<QColor>());
587
item->setLinePen(m_dashedLineGenerator->getBestPen(cl->m_format.getLineNumber(),
588
(Qt::PenStyle)cl->m_format.m_style,
589
cl->m_format.m_weight));
590
item->setWidth(Rez::guiX(cl->m_format.m_weight));
591
result = cl->m_format.m_visible;
596
QGIFace* QGIViewPart::drawFace(TechDraw::FacePtr f, int idx)
598
// Base::Console().Message("QGIVP::drawFace - %d\n", idx);
599
std::vector<TechDraw::Wire*> fWires = f->wires;
600
QPainterPath facePath;
601
for (std::vector<TechDraw::Wire*>::iterator wire = fWires.begin(); wire != fWires.end();
603
TechDraw::BaseGeomPtrVector geoms = (*wire)->geoms;
607
TechDraw::BaseGeomPtr firstGeom = geoms.front();
608
QPainterPath wirePath;
609
//QPointF startPoint(firstGeom->getStartPoint().x, firstGeom->getStartPoint().y);
610
//wirePath.moveTo(startPoint);
611
QPainterPath firstSeg = drawPainterPath(firstGeom);
612
wirePath.connectPath(firstSeg);
613
for (TechDraw::BaseGeomPtrVector::iterator edge = ((*wire)->geoms.begin()) + 1;
614
edge != (*wire)->geoms.end(); ++edge) {
615
QPainterPath edgePath = drawPainterPath(*edge);
616
//handle section faces differently
618
QPointF wEnd = wirePath.currentPosition();
619
auto element = edgePath.elementAt(0);
620
QPointF eStart(element.x, element.y);
621
QPointF eEnd = edgePath.currentPosition();
622
QPointF sVec = wEnd - eStart;
623
QPointF eVec = wEnd - eEnd;
624
double sDist2 = sVec.x() * sVec.x() + sVec.y() * sVec.y();
625
double eDist2 = eVec.x() * eVec.x() + eVec.y() * eVec.y();
626
if (sDist2 > eDist2) {
627
edgePath = edgePath.toReversed();
630
wirePath.connectPath(edgePath);
632
// dumpPath("wirePath:", wirePath);
633
facePath.addPath(wirePath);
635
facePath.setFillRule(Qt::OddEvenFill);
637
QGIFace* gFace = new QGIFace(idx);
639
gFace->setPos(0.0, 0.0);
640
gFace->setOutline(facePath);
642
//std::stringstream faceId;
643
//faceId << "facePath " << idx;
644
//dumpPath(faceId.str().c_str(), facePath);
649
//! Remove all existing QGIPrimPath items(Vertex, Edge, Face)
650
//note this triggers scene selectionChanged signal if vertex/edge/face is selected
651
void QGIViewPart::removePrimitives()
653
QList<QGraphicsItem*> children = childItems();
654
MDIViewPage* mdi = getMDIViewPage();
656
getMDIViewPage()->blockSceneSelection(true);
658
for (auto& c : children) {
659
QGIPrimPath* prim = dynamic_cast<QGIPrimPath*>(c);
662
scene()->removeItem(prim);
667
getMDIViewPage()->blockSceneSelection(false);
671
//! Remove all existing QGIDecoration items(SectionLine, SectionMark, ...)
672
void QGIViewPart::removeDecorations()
674
QList<QGraphicsItem*> children = childItems();
675
for (auto& c : children) {
676
QGIDecoration* decor = dynamic_cast<QGIDecoration*>(c);
677
QGIMatting* mat = dynamic_cast<QGIMatting*>(c);
680
scene()->removeItem(decor);
685
scene()->removeItem(mat);
691
void QGIViewPart::drawAllSectionLines()
693
TechDraw::DrawViewPart* viewPart = static_cast<TechDraw::DrawViewPart*>(getViewObject());
697
auto vp = static_cast<ViewProviderViewPart*>(getViewProvider(getViewObject()));
700
if (vp->ShowSectionLine.getValue()) {
701
auto refs = viewPart->getSectionRefs();
702
for (auto& r : refs) {
703
if (r->isDerivedFrom(DrawComplexSection::getClassTypeId())) {
704
drawComplexSectionLine(r, true);
707
drawSectionLine(r, true);
713
void QGIViewPart::drawSectionLine(TechDraw::DrawViewSection* viewSection, bool b)
715
// Base::Console().Message("QGIVP::drawSectionLine()\n");
716
TechDraw::DrawViewPart* viewPart = static_cast<TechDraw::DrawViewPart*>(getViewObject());
722
if (!viewSection->hasGeometry())
725
auto vp = static_cast<ViewProviderViewPart*>(getViewProvider(getViewObject()));
731
//find the ends of the section line
732
double scale = viewPart->getScale();
733
std::pair<Base::Vector3d, Base::Vector3d> sLineEnds = viewSection->sectionLineEnds();
734
Base::Vector3d l1 = Rez::guiX(sLineEnds.first) * scale;
735
Base::Vector3d l2 = Rez::guiX(sLineEnds.second) * scale;
736
if (l1.IsEqual(l2, EWTOLERANCE) ) {
737
Base::Console().Message("QGIVP::drawSectionLine - line endpoints are equal. No section line created.\n");
741
QGISectionLine* sectionLine = new QGISectionLine();
742
addToGroup(sectionLine);
743
sectionLine->setSymbol(const_cast<char*>(viewSection->SectionSymbol.getValue()));
744
App::Color color = Preferences::getAccessibleColor(vp->SectionLineColor.getValue());
745
sectionLine->setSectionColor(color.asValue<QColor>());
746
sectionLine->setPathMode(false);
748
//make the section line a little longer
749
double fudge = 2.0 * Preferences::dimFontSizeMM();
750
Base::Vector3d lineDir = l2 - l1;
752
sectionLine->setEnds(l1 - lineDir * Rez::guiX(fudge), l2 + lineDir * Rez::guiX(fudge));
754
//which way do the arrows point?
755
Base::Vector3d arrowDir = viewSection->SectionNormal.getValue();
756
arrowDir = -viewPart->projectPoint(arrowDir); //arrows point reverse of sectionNormal
757
sectionLine->setDirection(arrowDir.x, -arrowDir.y);//3d direction needs Y inversion
759
if (vp->SectionLineMarks.getValue()) {
760
ChangePointVector points = viewSection->getChangePointsFromSectionLine();
761
//extend the changePoint locations to match the fudged section line ends
762
QPointF location0 = points.front().getLocation() * scale;
763
location0 = location0 - DU::toQPointF(lineDir) * fudge;
764
QPointF location1 = points.back().getLocation() * scale;
765
location1 = location1 + DU::toQPointF(lineDir) * fudge;
766
//change points have Rez::guiX applied in sectionLine
767
points.front().setLocation(location0);
768
points.back().setLocation(location1);
769
sectionLine->setChangePoints(points);
772
sectionLine->clearChangePoints();
775
//set the general parameters
776
sectionLine->setPos(0.0, 0.0);
777
// sectionLines are typically ISO 8 (long dash, short dash) or ISO 4 (long dash, dot)
778
sectionLine->setLinePen(
779
m_dashedLineGenerator->getLinePen((size_t)vp->SectionLineStyle.getValue(),
780
vp->HiddenWidth.getValue()));
781
sectionLine->setWidth(Rez::guiX(vp->HiddenWidth.getValue()));
782
double fontSize = Preferences::dimFontSizeMM();
783
sectionLine->setFont(getFont(), fontSize);
784
sectionLine->setZValue(ZVALUE::SECTIONLINE);
785
sectionLine->setRotation(-viewPart->Rotation.getValue());
790
void QGIViewPart::drawComplexSectionLine(TechDraw::DrawViewSection* viewSection, bool b)
794
TechDraw::DrawViewPart* viewPart = static_cast<TechDraw::DrawViewPart*>(getViewObject());
799
auto vp = static_cast<ViewProviderViewPart*>(getViewProvider(getViewObject()));
804
auto dcs = static_cast<DrawComplexSection*>(viewSection);
805
std::pair<Base::Vector3d, Base::Vector3d> ends = dcs->sectionLineEnds();
806
Base::Vector3d vStart = Rez::guiX(ends.first);//already scaled by dcs
807
Base::Vector3d vEnd = Rez::guiX(ends.second);
808
if (vStart.IsEqual(vEnd, EWTOLERANCE) ) {
809
Base::Console().Message("QGIVP::drawComplexSectionLine - line endpoints are equal. No section line created.\n");
814
BaseGeomPtrVector edges = dcs->makeSectionLineGeometry();
815
QPainterPath wirePath;
816
QPainterPath firstSeg = drawPainterPath(edges.front());
817
wirePath.connectPath(firstSeg);
818
int edgeCount = edges.size();
819
//NOTE: if the edges are not in nose to tail order, Qt will insert extra segments
820
//that will overlap the segments we add. for interrupted line styles, this
821
//will make the line look continuous. This is prevented in
822
//DrawComplexSection::makeSectionLineGeometry by calling makeNoseToTailWire
823
for (int i = 1; i < edgeCount; i++) {
824
QPainterPath edgePath = drawPainterPath(edges.at(i));
825
wirePath.connectPath(edgePath);
829
QGISectionLine* sectionLine = new QGISectionLine();
830
addToGroup(sectionLine);
831
sectionLine->setSymbol(const_cast<char*>(viewSection->SectionSymbol.getValue()));
832
App::Color color = Preferences::getAccessibleColor(vp->SectionLineColor.getValue());
833
sectionLine->setSectionColor(color.asValue<QColor>());
834
sectionLine->setPathMode(true);
835
sectionLine->setPath(wirePath);
836
sectionLine->setEnds(vStart, vEnd);
837
if (vp->SectionLineMarks.getValue()) {
838
sectionLine->setChangePoints(dcs->getChangePointsFromSectionLine());
841
sectionLine->clearChangePoints();
843
if (dcs->ProjectionStrategy.isValue("Offset")) {
844
Base::Vector3d arrowDirOffset = viewSection->SectionNormal.getValue();
846
-viewPart->projectPoint(arrowDirOffset);//arrows are opposite section normal
847
sectionLine->setDirection(arrowDirOffset.x, -arrowDirOffset.y);//invert y for Qt
850
std::pair<Base::Vector3d, Base::Vector3d> dirsAligned = dcs->sectionArrowDirs();
851
dirsAligned.first = DrawUtil::invertY(dirsAligned.first);
852
dirsAligned.second = DrawUtil::invertY(dirsAligned.second);
853
sectionLine->setArrowDirections(dirsAligned.first, dirsAligned.second);
856
//set the general parameters
857
sectionLine->setPos(0.0, 0.0);
858
// sectionLines are typically ISO 8 (long dash, short dash) or ISO 4 (long dash, dot)
859
sectionLine->setLinePen(
860
m_dashedLineGenerator->getLinePen((size_t)vp->SectionLineStyle.getValue(),
861
vp->HiddenWidth.getValue()));
862
sectionLine->setWidth(Rez::guiX(vp->HiddenWidth.getValue()));
863
double fontSize = Preferences::dimFontSizeMM();
864
sectionLine->setFont(getFont(), fontSize);
865
sectionLine->setZValue(ZVALUE::SECTIONLINE);
866
sectionLine->setRotation(-viewPart->Rotation.getValue());
870
//TODO: use Cosmetic::CenterLine object for this to make it usable for dims.
871
// these are the view center lines (ie x,y axes)
872
void QGIViewPart::drawCenterLines(bool b)
874
TechDraw::DrawViewPart* viewPart = dynamic_cast<TechDraw::DrawViewPart*>(getViewObject());
878
auto vp = static_cast<ViewProviderViewPart*>(getViewProvider(getViewObject()));
883
bool horiz = vp->HorizCenterLine.getValue();
884
bool vert = vp->VertCenterLine.getValue();
886
QGICenterLine* centerLine;
888
double sectionFudge = Rez::guiX(10.0);
891
centerLine = new QGICenterLine();
892
addToGroup(centerLine);
893
centerLine->setPos(0.0, 0.0);
894
double width = Rez::guiX(viewPart->getBoxX());
895
sectionSpan = width + sectionFudge;
896
xVal = sectionSpan / 2.0;
898
centerLine->setIntersection(horiz && vert);
899
centerLine->setBounds(-xVal, -yVal, xVal, yVal);
900
centerLine->setLinePen(m_dashedLineGenerator->getLinePen((size_t)Preferences::CenterLineStyle(),
901
vp->HiddenWidth.getValue()));
902
centerLine->setWidth(Rez::guiX(vp->HiddenWidth.getValue()));
903
centerLine->setColor(Qt::green);
904
centerLine->setZValue(ZVALUE::SECTIONLINE);
908
centerLine = new QGICenterLine();
909
addToGroup(centerLine);
910
centerLine->setPos(0.0, 0.0);
911
double height = Rez::guiX(viewPart->getBoxY());
912
sectionSpan = height + sectionFudge;
914
yVal = sectionSpan / 2.0;
915
centerLine->setIntersection(horiz && vert);
916
centerLine->setBounds(-xVal, -yVal, xVal, yVal);
917
centerLine->setLinePen(m_dashedLineGenerator->getLinePen((size_t)Preferences::CenterLineStyle(),
918
vp->HiddenWidth.getValue()));
919
centerLine->setWidth(Rez::guiX(vp->HiddenWidth.getValue()));
920
centerLine->setColor(Qt::red);
921
centerLine->setZValue(ZVALUE::SECTIONLINE);
927
void QGIViewPart::drawAllHighlights()
929
// dvp and vp already validated
930
auto dvp(static_cast<TechDraw::DrawViewPart*>(getViewObject()));
932
auto drefs = dvp->getDetailRefs();
933
for (auto& r : drefs) {
934
drawHighlight(r, true);
938
void QGIViewPart::drawHighlight(TechDraw::DrawViewDetail* viewDetail, bool b)
940
TechDraw::DrawViewPart* viewPart = static_cast<TechDraw::DrawViewPart*>(getViewObject());
941
if (!viewPart || !viewDetail) {
945
auto vp = static_cast<ViewProviderViewPart*>(getViewProvider(getViewObject()));
949
auto vpDetail = static_cast<ViewProviderViewPart*>(getViewProvider(viewDetail));
954
if (!viewDetail->ShowHighlight.getValue()) {
959
double fontSize = Preferences::labelFontSizeMM();
960
QGIHighlight* highlight = new QGIHighlight();
961
scene()->addItem(highlight);
962
highlight->setReference(viewDetail->Reference.getValue());
964
App::Color color = Preferences::getAccessibleColor(vp->HighlightLineColor.getValue());
965
highlight->setColor(color.asValue<QColor>());
966
highlight->setFeatureName(viewDetail->getNameInDocument());
967
highlight->setInteractive(true);
969
addToGroup(highlight);
970
highlight->setPos(0.0, 0.0);//sb setPos(center.x, center.y)?
972
Base::Vector3d center = viewDetail->AnchorPoint.getValue() * viewPart->getScale();
973
double rotationRad = viewPart->Rotation.getValue() * M_PI / 180.0;
974
center.RotateZ(rotationRad);
976
double radius = viewDetail->Radius.getValue() * viewPart->getScale();
977
highlight->setBounds(center.x - radius, center.y + radius, center.x + radius,
979
highlight->setLinePen(m_dashedLineGenerator->getLinePen((size_t)vp->HighlightLineStyle.getValue(),
980
vp->IsoWidth.getValue()));
981
highlight->setWidth(Rez::guiX(vp->IsoWidth.getValue()));
982
highlight->setFont(getFont(), fontSize);
983
highlight->setZValue(ZVALUE::HIGHLIGHT);
984
highlight->setReferenceAngle(vpDetail->HighlightAdjust.getValue());
986
//handle conversion of apparent X,Y to rotated
987
QPointF rotCenter = highlight->mapFromParent(transformOriginPoint());
988
highlight->setTransformOriginPoint(rotCenter);
990
double rotation = viewPart->Rotation.getValue();
991
highlight->setRotation(rotation);
996
void QGIViewPart::highlightMoved(QGIHighlight* highlight, QPointF newPos)
998
std::string highlightName = highlight->getFeatureName();
999
App::Document* doc = getViewObject()->getDocument();
1000
App::DocumentObject* docObj = doc->getObject(highlightName.c_str());
1001
auto detail = dynamic_cast<DrawViewDetail*>(docObj);
1003
auto oldAnchor = detail->AnchorPoint.getValue();
1004
Base::Vector3d delta = Rez::appX(DrawUtil::toVector3d(newPos)) / getViewObject()->getScale();
1005
delta = DrawUtil::invertY(delta);
1006
detail->AnchorPoint.setValue(oldAnchor + delta);
1010
void QGIViewPart::drawMatting()
1012
auto viewPart(dynamic_cast<TechDraw::DrawViewPart*>(getViewObject()));
1013
TechDraw::DrawViewDetail* dvd = nullptr;
1014
if (viewPart && viewPart->isDerivedFrom(TechDraw::DrawViewDetail::getClassTypeId())) {
1015
dvd = static_cast<TechDraw::DrawViewDetail*>(viewPart);
1021
if (!dvd->ShowMatting.getValue()) {
1025
double scale = dvd->getScale();
1026
double radius = dvd->Radius.getValue() * scale;
1027
QGIMatting* mat = new QGIMatting();
1029
mat->setRadius(Rez::guiX(radius));
1030
mat->setPos(0.0, 0.0);
1035
void QGIViewPart::toggleCache(bool state)
1037
QList<QGraphicsItem*> items = childItems();
1038
for (QList<QGraphicsItem*>::iterator it = items.begin(); it != items.end(); it++) {
1039
//(*it)->setCacheMode((state)? DeviceCoordinateCache : NoCache); //TODO: fiddle cache settings if req'd for performance
1041
(*it)->setCacheMode(NoCache);
1046
void QGIViewPart::toggleCosmeticLines(bool state)
1048
QList<QGraphicsItem*> items = childItems();
1049
for (QList<QGraphicsItem*>::iterator it = items.begin(); it != items.end(); it++) {
1050
QGIEdge* edge = dynamic_cast<QGIEdge*>(*it);
1052
edge->setCosmetic(state);
1057
//get hatchObj for face i if it exists
1058
TechDraw::DrawHatch* QGIViewPart::faceIsHatched(int i,
1059
std::vector<TechDraw::DrawHatch*> hatchObjs) const
1061
TechDraw::DrawHatch* result = nullptr;
1063
for (auto& h : hatchObjs) {
1064
const std::vector<std::string>& sourceNames = h->Source.getSubValues();
1065
for (auto& s : sourceNames) {
1066
int fdx = TechDraw::DrawUtil::getIndexFromName(s);
1080
TechDraw::DrawGeomHatch*
1081
QGIViewPart::faceIsGeomHatched(int i, std::vector<TechDraw::DrawGeomHatch*> geomObjs) const
1083
TechDraw::DrawGeomHatch* result = nullptr;
1085
for (auto& h : geomObjs) {
1086
const std::vector<std::string>& sourceNames = h->Source.getSubValues();
1087
for (auto& sn : sourceNames) {
1088
int fdx = TechDraw::DrawUtil::getIndexFromName(sn);
1104
void QGIViewPart::dumpPath(const char* text, QPainterPath path)
1106
QPainterPath::Element elem;
1107
Base::Console().Message(">>>%s has %d elements\n", text, path.elementCount());
1108
const char* typeName;
1109
for (int iElem = 0; iElem < path.elementCount(); iElem++) {
1110
elem = path.elementAt(iElem);
1111
if (elem.isMoveTo()) {
1112
typeName = "MoveTo";
1114
else if (elem.isLineTo()) {
1115
typeName = "LineTo";
1117
else if (elem.isCurveTo()) {
1118
typeName = "CurveTo";
1121
typeName = "CurveData";
1123
Base::Console().Message(">>>>> element %d: type:%d/%s pos(%.3f, %.3f) M:%d L:%d C:%d\n",
1124
iElem, static_cast<int>(elem.type), typeName, elem.x, elem.y, static_cast<int>(elem.isMoveTo()),
1125
static_cast<int>(elem.isLineTo()), static_cast<int>(elem.isCurveTo()));
1129
QRectF QGIViewPart::boundingRect() const
1131
// return childrenBoundingRect();
1132
// return customChildrenBoundingRect();
1133
return QGIView::boundingRect();
1135
void QGIViewPart::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
1137
QStyleOptionGraphicsItem myOption(*option);
1138
myOption.state &= ~QStyle::State_Selected;
1140
// painter->drawRect(boundingRect()); //good for debugging
1142
QGIView::paint(painter, &myOption, widget);
1145
//QGIViewPart derived classes do not need a rotate view method as rotation is handled on App side.
1146
void QGIViewPart::rotateView() {}
1148
bool QGIViewPart::prefFaceEdges()
1150
bool result = false;
1151
result = Preferences::getPreferenceGroup("General")->GetBool("DrawFaceEdges", false);
1155
bool QGIViewPart::prefPrintCenters()
1157
bool printCenters = Preferences::getPreferenceGroup("Decorations")->GetBool("PrintCenterMarks", false);//true matches v0.18 behaviour
1158
return printCenters;
1161
QGraphicsItem *QGIViewPart::getQGISubItemByName(const std::string &subName) const
1165
const std::string &subType = TechDraw::DrawUtil::getGeomTypeFromName(subName);
1166
if (subType == "Vertex") {
1167
scanType = QGIVertex::Type;
1169
else if (subType == "Edge") {
1170
scanType = QGIEdge::Type;
1172
else if (subType == "Face") {
1173
scanType = QGIFace::Type;
1176
catch (Base::ValueError&) {
1185
scanIndex = TechDraw::DrawUtil::getIndexFromName(subName);
1187
catch (Base::ValueError&) {
1190
if (scanIndex < 0) {
1194
for (auto child : childItems()) {
1195
if (child->type() != scanType) {
1201
case QGIVertex::Type:
1202
projIndex = static_cast<QGIVertex *>(child)->getProjIndex();
1205
projIndex = static_cast<QGIEdge *>(child)->getProjIndex();
1208
projIndex = static_cast<QGIFace *>(child)->getProjIndex();
1215
if (projIndex == scanIndex) {
1223
bool QGIViewPart::getGroupSelection() {
1224
return DrawGuiUtil::isSelectedInTree(this);
1227
void QGIViewPart::setGroupSelection(bool isSelected) {
1228
DrawGuiUtil::setSelectedTree(this, isSelected);
1231
void QGIViewPart::setGroupSelection(bool isSelected, const std::vector<std::string> &subNames)
1233
if (subNames.empty()) {
1234
setSelected(isSelected);
1238
for (const std::string &subName : subNames) {
1239
if (subName.empty()) {
1240
setSelected(isSelected);
1244
QGraphicsItem *subItem = getQGISubItemByName(subName);
1246
subItem->setSelected(isSelected);