/*************************************************************************** * Copyright (c) 2013 Luke Parry * * * * 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" #ifndef _PreComp_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif // #ifndef _PreComp_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Rez.h" #include "ZVALUE.h" #include "QGIFace.h" #include "QGIEdge.h" #include "QGIVertex.h" #include "QGICMark.h" #include "QGISectionLine.h" #include "QGICenterLine.h" #include "QGCustomBorder.h" #include "QGCustomLabel.h" #include "QGCustomRect.h" #include "QGIMatting.h" #include "QGIViewPart.h" #include "ViewProviderGeomHatch.h" using namespace TechDrawGui; using namespace TechDrawGeometry; const float lineScaleFactor = Rez::guiX(1.); // temp fiddle for devel const float vertexScaleFactor = 2.; // temp fiddle for devel QGIViewPart::QGIViewPart() { setCacheMode(QGraphicsItem::NoCache); setHandlesChildEvents(false); setAcceptHoverEvents(true); setFlag(QGraphicsItem::ItemIsSelectable, true); setFlag(QGraphicsItem::ItemIsMovable, true); setFlag(QGraphicsItem::ItemSendsScenePositionChanges, true); setFlag(QGraphicsItem::ItemSendsGeometryChanges,true); showSection = false; } QGIViewPart::~QGIViewPart() { tidy(); } QVariant QGIViewPart::itemChange(GraphicsItemChange change, const QVariant &value) { if (change == ItemSelectedHasChanged && scene()) { QList items = childItems(); for(QList::iterator it = items.begin(); it != items.end(); ++it) { //Highlight the children if this is highlighted!? seems to mess up Face selection? QGIEdge *edge = dynamic_cast(*it); QGIVertex *vert = dynamic_cast(*it); QGIFace *face = dynamic_cast(*it); if(edge) { //edge->setHighlighted(isSelected()); } else if(vert){ //vert->setHighlighted(isSelected()); } else if(face){ //face->setHighlighted(isSelected()); } } } else if(change == ItemSceneChange && scene()) { tidy(); } return QGIView::itemChange(change, value); } //obs? void QGIViewPart::tidy() { //Delete any leftover items for(QList::iterator it = deleteItems.begin(); it != deleteItems.end(); ++it) { delete *it; } deleteItems.clear(); } void QGIViewPart::setViewPartFeature(TechDraw::DrawViewPart *obj) { if (!obj) return; // called from QGVPage setViewFeature(static_cast(obj)); draw(); } QPainterPath QGIViewPart::drawPainterPath(TechDrawGeometry::BaseGeom *baseGeom) const { QPainterPath path; switch(baseGeom->geomType) { case TechDrawGeometry::CIRCLE: { TechDrawGeometry::Circle *geom = static_cast(baseGeom); double x = geom->center.x - geom->radius; double y = geom->center.y - geom->radius; path.addEllipse(Rez::guiX(x), Rez::guiX(y), Rez::guiX(geom->radius * 2), Rez::guiX(geom->radius * 2)); //topleft@(x,y) radx,rady //Base::Console().Message("TRACE -drawPainterPath - making an CIRCLE @(%.3f,%.3f) R:%.3f\n",x, y, geom->radius); } break; case TechDrawGeometry::ARCOFCIRCLE: { TechDrawGeometry::AOC *geom = static_cast(baseGeom); pathArc(path, Rez::guiX(geom->radius), Rez::guiX(geom->radius), 0., geom->largeArc, geom->cw, Rez::guiX(geom->endPnt.x), Rez::guiX(geom->endPnt.y), Rez::guiX(geom->startPnt.x), Rez::guiX(geom->startPnt.y)); // double x = geom->center.x - geom->radius; // double y = geom->center.y - geom->radius; //Base::Console().Message("TRACE -drawPainterPath - making an ARCOFCIRCLE @(%.3f,%.3f) R:%.3f\n",x, y, geom->radius); } break; case TechDrawGeometry::ELLIPSE: { TechDrawGeometry::Ellipse *geom = static_cast(baseGeom); // Calculate start and end points as ellipse with theta = 0 and pi double startX = geom->center.x + geom->major * cos(geom->angle), startY = geom->center.y + geom->major * sin(geom->angle), endX = geom->center.x - geom->major * cos(geom->angle), endY = geom->center.y - geom->major * sin(geom->angle); pathArc(path, Rez::guiX(geom->major), Rez::guiX(geom->minor), geom->angle, false, false, Rez::guiX(endX), Rez::guiX(endY), Rez::guiX(startX), Rez::guiX(startY)); pathArc(path, Rez::guiX(geom->major), Rez::guiX(geom->minor), geom->angle, false, false, Rez::guiX(startX), Rez::guiX(startY), Rez::guiX(endX), Rez::guiX(endY)); //Base::Console().Message("TRACE -drawPainterPath - making an ELLIPSE @(%.3f,%.3f) R1:%.3f R2:%.3f\n",geom->center.x,geom->center.y, geom->major, geom->minor); } break; case TechDrawGeometry::ARCOFELLIPSE: { TechDrawGeometry::AOE *geom = static_cast(baseGeom); pathArc(path, Rez::guiX(geom->major), Rez::guiX(geom->minor), geom->angle, geom->largeArc, geom->cw, Rez::guiX(geom->endPnt.x), Rez::guiX(geom->endPnt.y), Rez::guiX(geom->startPnt.x), Rez::guiX(geom->startPnt.y)); //Base::Console().Message("TRACE -drawPainterPath - making an ARCOFELLIPSE R1:%.3f R2:%.3f From: (%.3f,%.3f) To: (%.3f,%.3f)\n",geom->major, geom->minor,geom->startPnt.x, geom->startPnt.y,geom->endPnt.x, geom->endPnt.y); } break; case TechDrawGeometry::BEZIER: { TechDrawGeometry::BezierSegment *geom = static_cast(baseGeom); // Move painter to the beginning path.moveTo(Rez::guiX(geom->pnts[0].x), Rez::guiX(geom->pnts[0].y)); //Base::Console().Message("TRACE -drawPainterPath - making an BEZIER From: (%.3f,%.3f)\n",geom->pnts[0].x,geom->pnts[0].y); if ( geom->poles == 2 ) { // Degree 1 bezier = straight line... path.lineTo(Rez::guiX(geom->pnts[1].x), Rez::guiX(geom->pnts[1].y)); } else if ( geom->poles == 3 ) { path.quadTo(Rez::guiX(geom->pnts[1].x), Rez::guiX(geom->pnts[1].y), Rez::guiX(geom->pnts[2].x), Rez::guiX(geom->pnts[2].y)); } else if ( geom->poles == 4 ) { path.cubicTo(Rez::guiX(geom->pnts[1].x), Rez::guiX(geom->pnts[1].y), Rez::guiX(geom->pnts[2].x), Rez::guiX(geom->pnts[2].y), Rez::guiX(geom->pnts[3].x), Rez::guiX(geom->pnts[3].y)); } else { //can only handle lines,quads,cubes Base::Console().Error("Bad pole count (%d) for BezierSegment\n",geom->poles); auto itBez = geom->pnts.begin() + 1; for (; itBez != geom->pnts.end();itBez++) { path.lineTo(Rez::guiX((*itBez).x), Rez::guiX((*itBez).y)); //show something for debugging } } } break; case TechDrawGeometry::BSPLINE: { TechDrawGeometry::BSpline *geom = static_cast(baseGeom); std::vector::const_iterator it = geom->segments.begin(); // Move painter to the beginning of our first segment path.moveTo(Rez::guiX(it->pnts[0].x), Rez::guiX(it->pnts[0].y)); //Base::Console().Message("TRACE -drawPainterPath - making an BSPLINE From: (%.3f,%.3f)\n",it->pnts[0].x,it->pnts[0].y); for ( ; it != geom->segments.end(); ++it) { // At this point, the painter is either at the beginning // of the first segment, or end of the last if ( it->poles == 2 ) { // Degree 1 bezier = straight line... path.lineTo(Rez::guiX(it->pnts[1].x), Rez::guiX(it->pnts[1].y)); } else if ( it->poles == 3 ) { path.quadTo(Rez::guiX(it->pnts[1].x), Rez::guiX(it->pnts[1].y), Rez::guiX(it->pnts[2].x), Rez::guiX(it->pnts[2].y)); } else if ( it->poles == 4 ) { path.cubicTo(Rez::guiX(it->pnts[1].x), Rez::guiX(it->pnts[1].y), Rez::guiX(it->pnts[2].x), Rez::guiX(it->pnts[2].y), Rez::guiX(it->pnts[3].x), Rez::guiX(it->pnts[3].y)); } else { //can only handle lines,quads,cubes Base::Console().Error("Bad pole count (%d) for BezierSegment of BSpline geometry\n",it->poles); path.lineTo(it->pnts[1].x, it->pnts[1].y); //show something for debugging } } } break; case TechDrawGeometry::GENERIC: { TechDrawGeometry::Generic *geom = static_cast(baseGeom); path.moveTo(Rez::guiX(geom->points[0].x), Rez::guiX(geom->points[0].y)); std::vector::const_iterator it = geom->points.begin(); //Base::Console().Message("TRACE -drawPainterPath - making an GENERIC From: (%.3f,%.3f)\n",geom->points[0].x, geom->points[0].y); for(++it; it != geom->points.end(); ++it) { path.lineTo(Rez::guiX((*it).x), Rez::guiX((*it).y)); //Base::Console().Message(">>>> To: (%.3f,%.3f)\n",(*it).x, (*it).y); } } break; default: Base::Console().Error("Error - drawPainterPath - UNKNOWN geomType: %d\n",baseGeom->geomType); break; } double rot = getViewObject()->Rotation.getValue(); if (rot) { QTransform t; t.rotate(-rot); path = t.map(path); } return path; } void QGIViewPart::updateView(bool update) { auto viewPart( dynamic_cast(getViewObject()) ); if( viewPart == nullptr ) { return; } QGIView::updateView(update); if (update || viewPart->isTouched() || viewPart->Source.isTouched() || viewPart->Direction.isTouched() || viewPart->Rotation.isTouched() || viewPart->Scale.isTouched() || viewPart->HardHidden.isTouched() || viewPart->SmoothVisible.isTouched() || viewPart->SeamVisible.isTouched() || viewPart->IsoVisible.isTouched() || viewPart->SmoothHidden.isTouched() || viewPart->SeamHidden.isTouched() || viewPart->IsoHidden.isTouched() || viewPart->IsoCount.isTouched() || viewPart->ShowSectionLine.isTouched() || viewPart->HorizCenterLine.isTouched() || viewPart->VertCenterLine.isTouched() ) { draw(); } else if (update || viewPart->LineWidth.isTouched() || viewPart->HiddenWidth.isTouched()) { QList items = childItems(); for(QList::iterator it = items.begin(); it != items.end(); ++it) { QGIEdge *edge = dynamic_cast(*it); if(edge && edge->getHiddenEdge()) { edge->setWidth(viewPart->HiddenWidth.getValue() * lineScaleFactor); } else if (edge){ edge->setWidth(viewPart->LineWidth.getValue() * lineScaleFactor); } } draw(); } else { QGIView::draw(); } } void QGIViewPart::draw() { drawViewPart(); drawMatting(); // drawBorder(); QGIView::draw(); } void QGIViewPart::drawViewPart() { auto viewPart( dynamic_cast(getViewObject()) ); if ( viewPart == nullptr ) { return; } if (!viewPart->hasGeometry()) { return; } float lineWidth = viewPart->LineWidth.getValue() * lineScaleFactor; float lineWidthHid = viewPart->HiddenWidth.getValue() * lineScaleFactor; float lineWidthIso = viewPart->IsoWidth.getValue() * lineScaleFactor; prepareGeometryChange(); removePrimitives(); //clean the slate removeDecorations(); #if MOD_TECHDRAW_HANDLE_FACES if (viewPart->handleFaces()) { // Draw Faces std::vector hatchObjs = viewPart->getHatches(); std::vector geomObjs = viewPart->getGeomHatches(); const std::vector &faceGeoms = viewPart->getFaceGeometry(); std::vector::const_iterator fit = faceGeoms.begin(); for(int i = 0 ; fit != faceGeoms.end(); fit++, i++) { QGIFace* newFace = drawFace(*fit,i); newFace->isHatched(false); newFace->setFillMode(QGIFace::PlainFill); TechDraw::DrawHatch* fHatch = faceIsHatched(i,hatchObjs); TechDraw::DrawGeomHatch* fGeom = faceIsGeomHatched(i,geomObjs); if (fGeom) { const std::vector &sourceNames = fGeom->Source.getSubValues(); if (!sourceNames.empty()) { int fdx = TechDraw::DrawUtil::getIndexFromName(sourceNames.at(0)); std::vector lineSets = fGeom->getDrawableLines(fdx); if (!lineSets.empty()) { newFace->clearLineSets(); for (auto& ls: lineSets) { QPainterPath bigPath; for (auto& g: ls.getGeoms()) { QPainterPath smallPath = drawPainterPath(g); bigPath.addPath(smallPath); } newFace->addLineSet(bigPath,ls.getDashSpec()); } newFace->isHatched(true); newFace->setFillMode(QGIFace::GeomHatchFill); newFace->setHatchScale(fGeom->ScalePattern.getValue()); newFace->setHatchFile(fGeom->FilePattern.getValue()); Gui::ViewProvider* gvp = QGIView::getViewProvider(fGeom); ViewProviderGeomHatch* geomVp = dynamic_cast(gvp); if (geomVp != nullptr) { newFace->setHatchColor(geomVp->ColorPattern.getValue()); newFace->setLineWeight(geomVp->WeightPattern.getValue()); } } } } else if (fHatch) { if (!fHatch->HatchPattern.isEmpty()) { newFace->isHatched(true); newFace->setFillMode(QGIFace::FromFile); newFace->setHatchFile(fHatch->HatchPattern.getValue()); newFace->setHatchScale(fHatch->HatchScale.getValue()); newFace->setHatchColor(fHatch->HatchColor.getValue()); } } bool drawEdges = getFaceEdgesPref(); newFace->setDrawEdges(drawEdges); //pref. for debugging only newFace->setZValue(ZVALUE::FACE); newFace->draw(); newFace->setPrettyNormal(); } } #endif //#if MOD_TECHDRAW_HANDLE_FACES // Draw Edges const std::vector &geoms = viewPart->getEdgeGeometry(); std::vector::const_iterator itEdge = geoms.begin(); QGIEdge* item; for(int i = 0 ; itEdge != geoms.end(); itEdge++, i++) { bool showEdge = false; if ((*itEdge)->visible) { if (((*itEdge)->classOfEdge == ecHARD) || ((*itEdge)->classOfEdge == ecOUTLINE) || (((*itEdge)->classOfEdge == ecSMOOTH) && viewPart->SmoothVisible.getValue()) || (((*itEdge)->classOfEdge == ecSEAM) && viewPart->SeamVisible.getValue()) || (((*itEdge)->classOfEdge == ecUVISO) && viewPart->IsoVisible.getValue())) { showEdge = true; } } else { if ( (((*itEdge)->classOfEdge == ecHARD) && (viewPart->HardHidden.getValue())) || (((*itEdge)->classOfEdge == ecOUTLINE) && (viewPart->HardHidden.getValue())) || (((*itEdge)->classOfEdge == ecSMOOTH) && (viewPart->SmoothHidden.getValue())) || (((*itEdge)->classOfEdge == ecSEAM) && (viewPart->SeamHidden.getValue())) || (((*itEdge)->classOfEdge == ecUVISO) && (viewPart->IsoHidden.getValue())) ) { showEdge = true; } } if (showEdge) { item = new QGIEdge(i); addToGroup(item); //item is at scene(0,0), not group(0,0) item->setPos(0.0,0.0); //now at group(0,0) item->setPath(drawPainterPath(*itEdge)); item->setWidth(lineWidth); item->setZValue(ZVALUE::EDGE); if(!(*itEdge)->visible) { item->setWidth(lineWidthHid); item->setHiddenEdge(true); item->setZValue(ZVALUE::HIDEDGE); } if ((*itEdge)->classOfEdge == ecUVISO) { item->setWidth(lineWidthIso); } item->setPrettyNormal(); //debug a path // QPainterPath edgePath=drawPainterPath(*itEdge); // std::stringstream edgeId; // edgeId << "QGIVP.edgePath" << i; // dumpPath(edgeId.str().c_str(),edgePath); } } // Draw Vertexs: const std::vector &verts = viewPart->getVertexGeometry(); std::vector::const_iterator vert = verts.begin(); bool showCenters = viewPart->ArcCenterMarks.getValue(); double cAdjust = viewPart->CenterScale.getValue(); for(int i = 0 ; vert != verts.end(); ++vert, i++) { if ((*vert)->isCenter) { if (showCenters) { QGICMark* cmItem = new QGICMark(i); addToGroup(cmItem); cmItem->setPos(Rez::guiX((*vert)->pnt.x), Rez::guiX((*vert)->pnt.y)); cmItem->setThick(0.5 * lineWidth); //need minimum? cmItem->setSize( cAdjust * lineWidth * vertexScaleFactor); cmItem->setZValue(ZVALUE::VERTEX); } } else { QGIVertex *item = new QGIVertex(i); addToGroup(item); item->setPos(Rez::guiX((*vert)->pnt.x), Rez::guiX((*vert)->pnt.y)); item->setRadius(lineWidth * vertexScaleFactor); item->setZValue(ZVALUE::VERTEX); } } //draw section line if (viewPart->ShowSectionLine.getValue()) { auto refs = viewPart->getSectionRefs(); for (auto& r:refs) { drawSectionLine(r, true); } } //draw center lines drawCenterLines(true); } QGIFace* QGIViewPart::drawFace(TechDrawGeometry::Face* f, int idx) { std::vector fWires = f->wires; QPainterPath facePath; for(std::vector::iterator wire = fWires.begin(); wire != fWires.end(); ++wire) { QPainterPath wirePath; for(std::vector::iterator edge = (*wire)->geoms.begin(); edge != (*wire)->geoms.end(); ++edge) { //Save the start Position QPainterPath edgePath = drawPainterPath(*edge); // If the current end point matches the shape end point the new edge path needs reversing QPointF shapePos = (wirePath.currentPosition()- edgePath.currentPosition()); if(sqrt(shapePos.x() * shapePos.x() + shapePos.y()*shapePos.y()) < 0.05) { //magic tolerance edgePath = edgePath.toReversed(); } wirePath.connectPath(edgePath); } //dumpPath("wirePath:",wirePath); facePath.addPath(wirePath); } facePath.setFillRule(Qt::OddEvenFill); QGIFace* gFace = new QGIFace(idx); addToGroup(gFace); gFace->setPos(0.0,0.0); gFace->setOutline(facePath); //debug a path //std::stringstream faceId; //faceId << "facePath " << idx; //dumpPath(faceId.str().c_str(),facePath); return gFace; } //! Remove all existing QGIPrimPath items(Vertex,Edge,Face) void QGIViewPart::removePrimitives() { QList children = childItems(); for (auto& c:children) { QGIPrimPath* prim = dynamic_cast(c); if (prim) { removeFromGroup(prim); scene()->removeItem(prim); // deleteItems.append(prim); //pretty sure we could just delete here since not in scene anymore delete prim; } } } //! Remove all existing QGIDecoration items(SectionLine,SectionMark,...) void QGIViewPart::removeDecorations() { QList children = childItems(); for (auto& c:children) { QGIDecoration* decor = dynamic_cast(c); QGIMatting* mat = dynamic_cast(c); if (decor) { removeFromGroup(decor); scene()->removeItem(decor); delete decor; } else if (mat) { removeFromGroup(mat); scene()->removeItem(mat); delete mat; } } } void QGIViewPart::drawSectionLine(TechDraw::DrawViewSection* viewSection, bool b) { TechDraw::DrawViewPart *viewPart = static_cast(getViewObject()); if (!viewPart || !viewSection) { return; } if (!viewSection->hasGeometry()) { return; } if (b) { QGISectionLine* sectionLine = new QGISectionLine(); addToGroup(sectionLine); sectionLine->setSymbol(const_cast(viewSection->SectionSymbol.getValue())); //TODO: handle oblique section lines? //find smallest internal angle(normalDir,get?Dir()) and use -1*get?Dir() +/- angle //Base::Vector3d normalDir = viewSection->SectionNormal.getValue(); Base::Vector3d arrowDir(0,1,0); //for drawing only, not geom Base::Vector3d lineDir(1,0,0); bool horiz = false; if (viewSection->SectionDirection.isValue("Right")) { arrowDir = Base::Vector3d(1,0,0); lineDir = Base::Vector3d(0,1,0); } else if (viewSection->SectionDirection.isValue("Left")) { arrowDir = Base::Vector3d(-1,0,0); lineDir = Base::Vector3d(0,-1,0); } else if (viewSection->SectionDirection.isValue("Up")) { arrowDir = Base::Vector3d(0,1,0); lineDir = Base::Vector3d(1,0,0); horiz = true; } else if (viewSection->SectionDirection.isValue("Down")) { arrowDir = Base::Vector3d(0,-1,0); lineDir = Base::Vector3d(-1,0,0); horiz = true; } sectionLine->setDirection(arrowDir.x,arrowDir.y); Base::Vector3d org = viewSection->SectionOrigin.getValue(); double scale = viewPart->Scale.getValue(); Base::Vector3d pOrg = scale * viewPart->projectPoint(org); //now project pOrg onto arrowDir Base::Vector3d displace; displace.ProjectToLine(pOrg, arrowDir); Base::Vector3d offset = pOrg + displace; sectionLine->setPos(Rez::guiX(offset.x),Rez::guiX(offset.y)); double sectionSpan; double sectionFudge = Rez::guiX(10.0); double xVal, yVal; if (horiz) { sectionSpan = m_border->rect().width() + sectionFudge; xVal = sectionSpan / 2.0; yVal = 0.0; } else { sectionSpan = (m_border->rect().height() - m_label->boundingRect().height()) + sectionFudge; xVal = 0.0; yVal = sectionSpan / 2.0; } sectionLine->setBounds(-xVal,-yVal,xVal,yVal); sectionLine->setWidth(Rez::guiX(viewPart->LineWidth.getValue())); //TODO: add fudge to make sectionLine thinner than reg lines? sectionLine->setFont(m_font,Rez::guiX(6.0)); sectionLine->setZValue(ZVALUE::SECTIONLINE); sectionLine->setRotation(- viewPart->Rotation.getValue()); sectionLine->draw(); } } void QGIViewPart::drawCenterLines(bool b) { TechDraw::DrawViewPart *viewPart = dynamic_cast(getViewObject()); if (!viewPart) { return; } if (b) { bool horiz = viewPart->HorizCenterLine.getValue(); bool vert = viewPart->VertCenterLine.getValue(); QGICenterLine* centerLine; double sectionSpan; double sectionFudge = 10.0; double xVal, yVal; if (horiz) { centerLine = new QGICenterLine(); addToGroup(centerLine); centerLine->setPos(0.0,0.0); sectionSpan = m_border->rect().width() + sectionFudge; xVal = sectionSpan / 2.0; yVal = 0.0; centerLine->setBounds(-xVal,-yVal,xVal,yVal); //centerLine->setWidth(viewPart->LineWidth.getValue()); centerLine->setZValue(ZVALUE::SECTIONLINE); centerLine->setRotation(- viewPart->Rotation.getValue()); centerLine->draw(); } if (vert) { centerLine = new QGICenterLine(); addToGroup(centerLine); centerLine->setPos(0.0,0.0); sectionSpan = (m_border->rect().height() - m_label->boundingRect().height()) + sectionFudge; xVal = 0.0; yVal = sectionSpan / 2.0; centerLine->setBounds(-xVal,-yVal,xVal,yVal); //centerLine->setWidth(viewPart->LineWidth.getValue()); centerLine->setZValue(ZVALUE::SECTIONLINE); centerLine->setRotation(- viewPart->Rotation.getValue()); centerLine->draw(); } } } void QGIViewPart::drawMatting() { auto viewPart( dynamic_cast(getViewObject()) ); TechDraw::DrawViewDetail* dvd = nullptr; if (viewPart && viewPart->isDerivedFrom(TechDraw::DrawViewDetail::getClassTypeId())) { dvd = static_cast(viewPart); } else { return; } double scale = dvd->Scale.getValue(); double radius = dvd->Radius.getValue() * scale; QGIMatting* mat = new QGIMatting(); addToGroup(mat); mat->setRadius(Rez::guiX(radius)); mat->setPos(0.0,0.0); mat->draw(); mat->show(); } // As called by arc of ellipse case: // pathArc(path, geom->major, geom->minor, geom->angle, geom->largeArc, geom->cw, // geom->endPnt.x, geom->endPnt.y, // geom->startPnt.x, geom->startPnt.y); void QGIViewPart::pathArc(QPainterPath &path, double rx, double ry, double x_axis_rotation, bool large_arc_flag, bool sweep_flag, double x, double y, double curx, double cury) const { double sin_th, cos_th; double a00, a01, a10, a11; double x0, y0, x1, y1, xc, yc; double d, sfactor, sfactor_sq; double th0, th1, th_arc; int i, n_segs; double dx, dy, dx1, dy1, Pr1, Pr2, Px, Py, check; rx = qAbs(rx); ry = qAbs(ry); sin_th = qSin(x_axis_rotation); cos_th = qCos(x_axis_rotation); dx = (curx - x) / 2.0; dy = (cury - y) / 2.0; dx1 = cos_th * dx + sin_th * dy; dy1 = -sin_th * dx + cos_th * dy; Pr1 = rx * rx; Pr2 = ry * ry; Px = dx1 * dx1; Py = dy1 * dy1; /* Spec : check if radii are large enough */ check = Px / Pr1 + Py / Pr2; if (check > 1) { rx = rx * qSqrt(check); ry = ry * qSqrt(check); } a00 = cos_th / rx; a01 = sin_th / rx; a10 = -sin_th / ry; a11 = cos_th / ry; x0 = a00 * curx + a01 * cury; y0 = a10 * curx + a11 * cury; x1 = a00 * x + a01 * y; y1 = a10 * x + a11 * y; /* (x0, y0) is current point in transformed coordinate space. (x1, y1) is new point in transformed coordinate space. The arc fits a unit-radius circle in this space. */ d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0); sfactor_sq = 1.0 / d - 0.25; if (sfactor_sq < 0) sfactor_sq = 0; sfactor = qSqrt(sfactor_sq); if (sweep_flag == large_arc_flag) sfactor = -sfactor; xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0); yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0); /* (xc, yc) is center of the circle. */ th0 = qAtan2(y0 - yc, x0 - xc); th1 = qAtan2(y1 - yc, x1 - xc); th_arc = th1 - th0; if (th_arc < 0 && sweep_flag) th_arc += 2 * M_PI; else if (th_arc > 0 && !sweep_flag) th_arc -= 2 * M_PI; n_segs = qCeil(qAbs(th_arc / (M_PI * 0.5 + 0.001))); path.moveTo(curx, cury); for (i = 0; i < n_segs; i++) { pathArcSegment(path, xc, yc, th0 + i * th_arc / n_segs, th0 + (i + 1) * th_arc / n_segs, rx, ry, x_axis_rotation); } } void QGIViewPart::pathArcSegment(QPainterPath &path, double xc, double yc, double th0, double th1, double rx, double ry, double xAxisRotation) const { double sinTh, cosTh; double a00, a01, a10, a11; double x1, y1, x2, y2, x3, y3; double t; double thHalf; sinTh = qSin(xAxisRotation); cosTh = qCos(xAxisRotation); a00 = cosTh * rx; a01 = -sinTh * ry; a10 = sinTh * rx; a11 = cosTh * ry; thHalf = 0.5 * (th1 - th0); t = (8.0 / 3.0) * qSin(thHalf * 0.5) * qSin(thHalf * 0.5) / qSin(thHalf); x1 = xc + qCos(th0) - t * qSin(th0); y1 = yc + qSin(th0) + t * qCos(th0); x3 = xc + qCos(th1); y3 = yc + qSin(th1); x2 = x3 + t * qSin(th1); y2 = y3 - t * qCos(th1); path.cubicTo(a00 * x1 + a01 * y1, a10 * x1 + a11 * y1, a00 * x2 + a01 * y2, a10 * x2 + a11 * y2, a00 * x3 + a01 * y3, a10 * x3 + a11 * y3); } void QGIViewPart::toggleCache(bool state) { QList items = childItems(); for(QList::iterator it = items.begin(); it != items.end(); it++) { //(*it)->setCacheMode((state)? DeviceCoordinateCache : NoCache); //TODO: fiddle cache settings if req'd for performance Q_UNUSED(state); (*it)->setCacheMode(NoCache); (*it)->update(); } } void QGIViewPart::toggleCosmeticLines(bool state) { QList items = childItems(); for(QList::iterator it = items.begin(); it != items.end(); it++) { QGIEdge *edge = dynamic_cast(*it); if(edge) { edge->setCosmetic(state); } } } void QGIViewPart::toggleVertices(bool state) { QList items = childItems(); for(QList::iterator it = items.begin(); it != items.end(); it++) { QGIVertex *vert = dynamic_cast(*it); QGICMark *mark = dynamic_cast(*it); if(vert) { if (!mark) { //leave center marks showing if(state) vert->show(); else vert->hide(); } } } } TechDraw::DrawHatch* QGIViewPart::faceIsHatched(int i,std::vector hatchObjs) const { TechDraw::DrawHatch* result = nullptr; for (auto& h:hatchObjs) { const std::vector &sourceNames = h->Source.getSubValues(); int fdx = TechDraw::DrawUtil::getIndexFromName(sourceNames.at(0)); if (fdx == i) { result = h; break; } } return result; } TechDraw::DrawGeomHatch* QGIViewPart::faceIsGeomHatched(int i,std::vector geomObjs) const { TechDraw::DrawGeomHatch* result = nullptr; for (auto& h:geomObjs) { const std::vector &sourceNames = h->Source.getSubValues(); int fdx = TechDraw::DrawUtil::getIndexFromName(sourceNames.at(0)); if (fdx == i) { result = h; break; } } return result; } void QGIViewPart::dumpPath(const char* text,QPainterPath path) { QPainterPath::Element elem; Base::Console().Message(">>>%s has %d elements\n",text,path.elementCount()); char* typeName; for(int iElem = 0; iElem < path.elementCount(); iElem++) { elem = path.elementAt(iElem); if(elem.isMoveTo()) { typeName = "MoveTo"; } else if (elem.isLineTo()) { typeName = "LineTo"; } else if (elem.isCurveTo()) { typeName = "CurveTo"; } else { typeName = "CurveData"; } Base::Console().Message(">>>>> element %d: type:%d/%s pos(%.3f,%.3f) M:%d L:%d C:%d\n",iElem, elem.type,typeName,elem.x,elem.y,elem.isMoveTo(),elem.isLineTo(),elem.isCurveTo()); } } QRectF QGIViewPart::boundingRect() const { return childrenBoundingRect(); } bool QGIViewPart::getFaceEdgesPref(void) { bool result = false; Base::Reference hGrp = App::GetApplication().GetUserParameter() .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/General"); result = hGrp->GetBool("DrawFaceEdges", 0l); return result; }