From 3c8be7472c4d70b2e570de866db5b70236a59ae7 Mon Sep 17 00:00:00 2001 From: wandererfan Date: Fri, 20 Oct 2023 11:20:47 -0400 Subject: [PATCH] [TD]refactor QGIFace into 2 files - add PATPathMaker for the PAT hatch spec processing methods - remove PAT methods from QGIFace - remove obsolete conversion of svg hatch to pixmap --- src/Mod/TechDraw/Gui/CMakeLists.txt | 2 + src/Mod/TechDraw/Gui/PATPathMaker.cpp | 279 +++++++++++++++++++++ src/Mod/TechDraw/Gui/PATPathMaker.h | 79 ++++++ src/Mod/TechDraw/Gui/QGIFace.cpp | 335 +------------------------- src/Mod/TechDraw/Gui/QGIFace.h | 8 +- 5 files changed, 376 insertions(+), 327 deletions(-) create mode 100644 src/Mod/TechDraw/Gui/PATPathMaker.cpp create mode 100644 src/Mod/TechDraw/Gui/PATPathMaker.h diff --git a/src/Mod/TechDraw/Gui/CMakeLists.txt b/src/Mod/TechDraw/Gui/CMakeLists.txt index 2028ad43e3..9b77c388eb 100644 --- a/src/Mod/TechDraw/Gui/CMakeLists.txt +++ b/src/Mod/TechDraw/Gui/CMakeLists.txt @@ -235,6 +235,8 @@ SET(TechDrawGui_SRCS Widgets/CompassWidget.h Widgets/VectorEditWidget.cpp Widgets/VectorEditWidget.h + PATPathMaker.cpp + PATPathMaker.h ) SET(TechDrawGuiView_SRCS diff --git a/src/Mod/TechDraw/Gui/PATPathMaker.cpp b/src/Mod/TechDraw/Gui/PATPathMaker.cpp new file mode 100644 index 0000000000..57b41963e0 --- /dev/null +++ b/src/Mod/TechDraw/Gui/PATPathMaker.cpp @@ -0,0 +1,279 @@ +/*************************************************************************** + * Copyright (c) 2023 WandererFan * + * * + * 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 +#endif +#include + +#include +#include +#include +#include + +#include "Rez.h" +#include "PATPathMaker.h" + +using namespace TechDrawGui; +using namespace TechDraw; + +PATPathMaker::PATPathMaker(QGraphicsItem* parent, double lineWidth, double fillScale) : + m_parent(parent), + m_fillScale(fillScale), + m_lineWidth(lineWidth) +{ + m_maxSeg = Preferences::getPreferenceGroup("PAT")->GetInt("MaxSeg", 10000l); +} + + +/// convert the PAT line set to QGraphicsPathItems +void PATPathMaker::lineSetToFillItems(LineSet& ls) +{ + m_segCount = 0; + QPen pen = getPen(); + for (auto& geom : ls.getGeoms()) { + //geom is a tdGeometry representation of 1 line in the pattern + if (ls.isDashed()) { + double offset = 0.0; + Base::Vector3d pStart = ls.getPatternStartPoint(geom, offset, m_fillScale); + offset = Rez::guiX(offset); + Base::Vector3d gStart(geom->getStartPoint().x, + geom->getStartPoint().y, + 0.0); + Base::Vector3d gEnd(geom->getEndPoint().x, + geom->getEndPoint().y, + 0.0); + if (DrawUtil::fpCompare(offset, 0.0, 0.00001)) { //no offset + QGraphicsPathItem* item1 = lineFromPoints(pStart, gEnd, ls.getDashSpec()); + item1->setPen(pen); + m_fillItems.push_back(item1); + if (!pStart.IsEqual(gStart, 0.00001)) { + QGraphicsPathItem* item2 = lineFromPoints(pStart, gStart, ls.getDashSpec().reversed()); + item2->setPen(pen); + m_fillItems.push_back(item2); + } + } else { //offset - pattern start not in g + double remain = dashRemain(decodeDashSpec(ls.getDashSpec()), offset); + QGraphicsPathItem* shortItem = geomToStubbyLine(geom, remain, ls); + shortItem->setPen(pen); + m_fillItems.push_back(shortItem); + } + } else { //not dashed + QGraphicsPathItem* fillItem = geomToLine(geom, ls); + fillItem->setPen(pen); + m_fillItems.push_back(fillItem); + } + + if (m_segCount > m_maxSeg) { + Base::Console().Warning("PAT segment count exceeded: %ld\n", m_segCount); + break; + } + } +} + + +/// create a PAT fill line from 2 points and a dash configuration +QGraphicsPathItem* PATPathMaker::lineFromPoints(Base::Vector3d start, Base::Vector3d end, DashSpec ds) +{ + QGraphicsPathItem* fillItem = new QGraphicsPathItem(m_parent); + fillItem->setPath(dashedPPath(decodeDashSpec(ds), + Rez::guiX(start), + Rez::guiX(end))); + return fillItem; +} + + +/// create a PAT fill line from geometry +QGraphicsPathItem* PATPathMaker::geomToLine(TechDraw::BaseGeomPtr base, LineSet& ls) +{ + QGraphicsPathItem* fillItem = new QGraphicsPathItem(m_parent); + Base::Vector3d start(base->getStartPoint().x, + base->getStartPoint().y, + 0.0); + Base::Vector3d end(base->getEndPoint().x, + base->getEndPoint().y, + 0.0); + fillItem->setPath(dashedPPath(decodeDashSpec(ls.getDashSpec()), + Rez::guiX(start), + Rez::guiX(end))); + return fillItem; +} + + +//! make a fragment (length = remain) of a dashed line, with pattern starting at +offset +QGraphicsPathItem* PATPathMaker::geomToStubbyLine(TechDraw::BaseGeomPtr base, double remain, LineSet& ls) +{ + QGraphicsPathItem* fillItem = new QGraphicsPathItem(m_parent); + Base::Vector3d start(base->getStartPoint().x, + base->getStartPoint().y, + 0.0); + Base::Vector3d end(base->getEndPoint().x, + base->getEndPoint().y, + 0.0); + double origLen = (end - start).Length(); + + double appRemain = Rez::appX(remain); + Base::Vector3d newEnd = start + (ls.getUnitDir() * appRemain); + + double newLen = (newEnd - start).Length(); + + if (newLen > origLen) { + newEnd = end; + } + + double offset = Rez::guiX(m_fillScale * ls.getDashSpec().length()) - remain; + + fillItem->setPath(dashedPPath(offsetDash(decodeDashSpec(ls.getDashSpec()), offset), + Rez::guiX(start), + Rez::guiX(newEnd))); + m_fillItems.push_back(fillItem); + return fillItem; +} + + +//! convert from mm to scene units +std::vector PATPathMaker::decodeDashSpec(DashSpec patDash) +{ + double penWidth = Rez::guiX(m_lineWidth); + double scale = m_fillScale; + double minPen = 0.01; //avoid trouble with cosmetic pen (zero width)? + if (penWidth <= minPen) { + penWidth = minPen; + } + std::vector result; + for (auto& d: patDash.get()) { + double strokeLength; + if (DrawUtil::fpCompare(d, 0.0)) { //pat dot + strokeLength = penWidth; + } else { //pat mark/space + strokeLength = Rez::guiX(d); + } + result.push_back(scale * strokeLength); + } + return result; +} + +//! make a dashed QPainterPath from start to end in scene coords +QPainterPath PATPathMaker::dashedPPath(const std::vector dashPattern, const Base::Vector3d start, const Base::Vector3d end) +{ + QPainterPath result; + Base::Vector3d dir = (end - start); + dir.Normalize(); + result.moveTo(start.x, -start.y); + Base::Vector3d currentPos = start; + if (dashPattern.empty()) { + result.lineTo(end.x, -end.y); + m_segCount++; + } else { + double lineLength = (end - start).Length(); + double travel = 0.0; + Base::Vector3d lineProgress; + while (travel < lineLength) { + bool stop = false; + if (m_segCount > 10000) { + Base::Console().Warning("PAT segment count exceeded: %ld\n", m_segCount); + break; + } + + for (auto& d: dashPattern) { + travel += fabs(d); + Base::Vector3d segmentEnd = (currentPos + dir * fabs(d)); + if ((start - segmentEnd).Length() > lineLength) { //don't draw past end of line + segmentEnd = end; + stop = true; + } + if (d < 0.0) { + result.moveTo(segmentEnd.x, -segmentEnd.y); //space + } else { + result.lineTo(segmentEnd.x, -segmentEnd.y); //mark + } + if (stop) { + break; + } + m_segCount++; + currentPos = segmentEnd; + } + } + } + return result; +} + + +//! convert a dash pattern to an offset dash pattern (ie offset -> end) +// dashPattern & offset are already scaled. +std::vector PATPathMaker::offsetDash(const std::vector dashPattern, const double offset) +{ + std::vector result; + double length = 0.0; + for (auto& d: dashPattern) { + length += fabs(d); + } + if (offset > length) { + result = dashPattern; + return result; + } + //find the dash cell that includes offset + double accum = 0; + int i = 0; + for (auto& d:dashPattern) { + accum += fabs(d); + if (accum > offset) { + break; + } + i++; + } + + double firstCell = accum - offset; + if (dashPattern.at(i) < 0.0) { //offset found in a space cell + result.push_back(-1.0* firstCell); + } else { + result.push_back(firstCell); + } + unsigned int iCell = i + 1; + for ( ; iCell < dashPattern.size() ; iCell++) { + result.push_back(dashPattern.at(iCell)); + } + + return result; +} + + +//! find remaining length of a dash pattern after offset +double PATPathMaker::dashRemain(const std::vector dashPattern, const double offset) +{ + double length = 0.0; + for (auto& d: dashPattern) { + length += fabs(d); + } + if (offset > length) { + return 0.0; + } + return length - offset; +} + + diff --git a/src/Mod/TechDraw/Gui/PATPathMaker.h b/src/Mod/TechDraw/Gui/PATPathMaker.h new file mode 100644 index 0000000000..e54966f82f --- /dev/null +++ b/src/Mod/TechDraw/Gui/PATPathMaker.h @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (c) 2023 WandererFan * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef TECHDRAWGUI_PATPATHMAKER_H +#define TECHDRAWGUI_PATPATHMAKER_H + +#include + +#include +#include + +#include +#include + +namespace TechDrawGui +{ + +class PATPathMaker +{ +public: + explicit PATPathMaker(QGraphicsItem* parent = nullptr, double lineWidth = 0.50, double fillScale = 1.0); + ~PATPathMaker() = default; + + void setLineWidth(double width) { m_lineWidth = width; } + void setScale(double scale) { m_fillScale = scale; } + void setPen(QPen pen) { m_pen = pen; } + QPen getPen() { return m_pen; } + void setParent(QGraphicsItem* parent) { m_parent = parent; } + + void lineSetToFillItems(TechDraw::LineSet& ls); + +protected: + QGraphicsPathItem* geomToLine(TechDraw::BaseGeomPtr base, TechDraw::LineSet& ls); + QGraphicsPathItem* geomToStubbyLine(TechDraw::BaseGeomPtr base, double offset, TechDraw::LineSet& ls); + QGraphicsPathItem* lineFromPoints(Base::Vector3d start, Base::Vector3d end, TechDraw::DashSpec ds); + std::vector offsetDash(const std::vector dv, const double offset); + QPainterPath dashedPPath(const std::vector dv, const Base::Vector3d start, const Base::Vector3d end); + double dashRemain(const std::vector dv, const double offset); + double calcOffset(TechDraw::BaseGeomPtr g, TechDraw::LineSet ls); + std::vector decodeDashSpec(TechDraw::DashSpec d); + +private: + QGraphicsItem* m_parent; + QPainterPath m_geomhatch; //crosshatch fill lines + QPen m_pen; + + std::vector m_lineSets; + std::vector m_dashSpecs; + std::vector m_fillItems; + + + double m_fillScale; + double m_lineWidth; + long int m_segCount; + long int m_maxSeg; +}; + +} +#endif // TECHDRAWGUI_PATPATHMAKER_H + diff --git a/src/Mod/TechDraw/Gui/QGIFace.cpp b/src/Mod/TechDraw/Gui/QGIFace.cpp index f3008fc0ed..41ef9d008f 100644 --- a/src/Mod/TechDraw/Gui/QGIFace.cpp +++ b/src/Mod/TechDraw/Gui/QGIFace.cpp @@ -41,7 +41,6 @@ #include "PreferencesGui.h" #include "QGIFace.h" #include -#include "QGCustomImage.h" #include "QGCustomRect.h" #include "QGCustomSvg.h" #include "QGICMark.h" @@ -72,9 +71,6 @@ QGIFace::QGIFace(int index) : setPrettyNormal(); m_texture = QPixmap(); //empty texture - m_imageHatchArea = new QGCustomImage(); - m_imageHatchArea->setParentItem(this); - m_svgHatchArea = new QGCustomRect(); m_svgHatchArea->setParentItem(this); @@ -101,11 +97,13 @@ QGIFace::QGIFace(int index) : } m_sharedRender = new QSvgRenderer(); + m_patMaker = new PATPathMaker(this, 1.0, 1.0); } QGIFace::~QGIFace() { delete m_sharedRender; + delete m_patMaker; } /// redraw this face @@ -126,37 +124,27 @@ void QGIFace::draw() lineSetToFillItems(ls); } } - m_imageHatchArea->hide(); m_svgHatchArea->hide(); } else if (m_mode == SvgFill) { m_brush.setTexture(QPixmap()); m_fillNormal = m_fillDef; m_fillStyleCurrent = m_fillNormal; loadSvgHatch(m_fileSpec); - if (m_hideSvgTiles) { - //bitmap hatch doesn't need clipping - setFlag(QGraphicsItem::ItemClipsChildrenToShape, false); - buildPixHatch(); - m_svgHatchArea->hide(); - m_imageHatchArea->show(); - } else { - //SVG tiles need to be clipped - setFlag(QGraphicsItem::ItemClipsChildrenToShape, true); - buildSvgHatch(); - m_imageHatchArea->hide(); - m_svgHatchArea->show(); - } + //SVG tiles need to be clipped + setFlag(QGraphicsItem::ItemClipsChildrenToShape, true); + buildSvgHatch(); + m_svgHatchArea->show(); } else if (m_mode == BitmapFill) { m_fillStyleCurrent = Qt::TexturePattern; m_texture = textureFromBitmap(m_fileSpec); m_brush.setTexture(m_texture); + m_svgHatchArea->hide(); } else if (m_mode == PlainFill) { setFill(m_colNormalFill, m_fillNormal); - m_imageHatchArea->hide(); m_svgHatchArea->hide(); } } else { - m_imageHatchArea->hide(); + // face is not hatched m_svgHatchArea->hide(); } show(); @@ -262,103 +250,10 @@ void QGIFace::addLineSet(LineSet& ls) /// convert the PAT line set to QGraphicsPathItems void QGIFace::lineSetToFillItems(LineSet& ls) { - m_segCount = 0; - QPen pen = setGeomPen(); - for (auto& geom : ls.getGeoms()) { - //geom is a tdGeometry representation of 1 line in the pattern - if (ls.isDashed()) { - double offset = 0.0; - Base::Vector3d pStart = ls.getPatternStartPoint(geom, offset, m_fillScale); - offset = Rez::guiX(offset); - Base::Vector3d gStart(geom->getStartPoint().x, - geom->getStartPoint().y, - 0.0); - Base::Vector3d gEnd(geom->getEndPoint().x, - geom->getEndPoint().y, - 0.0); - if (DrawUtil::fpCompare(offset, 0.0, 0.00001)) { //no offset - QGraphicsPathItem* item1 = lineFromPoints(pStart, gEnd, ls.getDashSpec()); - item1->setPen(pen); - m_fillItems.push_back(item1); - if (!pStart.IsEqual(gStart, 0.00001)) { - QGraphicsPathItem* item2 = lineFromPoints(pStart, gStart, ls.getDashSpec().reversed()); - item2->setPen(pen); - m_fillItems.push_back(item2); - } - } else { //offset - pattern start not in g - double remain = dashRemain(decodeDashSpec(ls.getDashSpec()), offset); - QGraphicsPathItem* shortItem = geomToStubbyLine(geom, remain, ls); - shortItem->setPen(pen); - m_fillItems.push_back(shortItem); - } - } else { //not dashed - QGraphicsPathItem* fillItem = geomToLine(geom, ls); - fillItem->setPen(pen); - m_fillItems.push_back(fillItem); - } - - if (m_segCount > m_maxSeg) { - Base::Console().Warning("PAT segment count exceeded: %ld\n", m_segCount); - break; - } - } -} - -/// create a PAT fill line from 2 points and a dash configuration -QGraphicsPathItem* QGIFace::lineFromPoints(Base::Vector3d start, Base::Vector3d end, DashSpec ds) -{ - QGraphicsPathItem* fillItem = new QGraphicsPathItem(this); - fillItem->setPath(dashedPPath(decodeDashSpec(ds), - Rez::guiX(start), - Rez::guiX(end))); - return fillItem; -} - -/// create a PAT fill line from geometry -QGraphicsPathItem* QGIFace::geomToLine(TechDraw::BaseGeomPtr base, LineSet& ls) -{ - QGraphicsPathItem* fillItem = new QGraphicsPathItem(this); - Base::Vector3d start(base->getStartPoint().x, - base->getStartPoint().y, - 0.0); - Base::Vector3d end(base->getEndPoint().x, - base->getEndPoint().y, - 0.0); - fillItem->setPath(dashedPPath(decodeDashSpec(ls.getDashSpec()), - Rez::guiX(start), - Rez::guiX(end))); - return fillItem; -} - - -//! make a fragment (length = remain) of a dashed line, with pattern starting at +offset -QGraphicsPathItem* QGIFace::geomToStubbyLine(TechDraw::BaseGeomPtr base, double remain, LineSet& ls) -{ - QGraphicsPathItem* fillItem = new QGraphicsPathItem(this); - Base::Vector3d start(base->getStartPoint().x, - base->getStartPoint().y, - 0.0); - Base::Vector3d end(base->getEndPoint().x, - base->getEndPoint().y, - 0.0); - double origLen = (end - start).Length(); - - double appRemain = Rez::appX(remain); - Base::Vector3d newEnd = start + (ls.getUnitDir() * appRemain); - - double newLen = (newEnd - start).Length(); - - if (newLen > origLen) { - newEnd = end; - } - - double offset = Rez::guiX(m_fillScale * ls.getDashSpec().length()) - remain; - - fillItem->setPath(dashedPPath(offsetDash(decodeDashSpec(ls.getDashSpec()), offset), - Rez::guiX(start), - Rez::guiX(newEnd))); - m_fillItems.push_back(fillItem); - return fillItem; + m_patMaker->setLineWidth(Rez::guiX(m_geomWeight)); + m_patMaker->setScale(m_fillScale); + m_patMaker->setPen(setGeomPen()); + m_patMaker->lineSetToFillItems(ls); } QPen QGIFace::setGeomPen() @@ -370,123 +265,6 @@ QPen QGIFace::setGeomPen() return result; } -//! convert from mm to scene units -std::vector QGIFace::decodeDashSpec(DashSpec patDash) -{ - double penWidth = Rez::guiX(m_geomWeight); - double scale = m_fillScale; - double minPen = 0.01; //avoid trouble with cosmetic pen (zero width)? - if (penWidth <= minPen) { - penWidth = minPen; - } - std::vector result; - for (auto& d: patDash.get()) { - double strokeLength; - if (DrawUtil::fpCompare(d, 0.0)) { //pat dot - strokeLength = penWidth; - } else { //pat mark/space - strokeLength = Rez::guiX(d); - } - result.push_back(scale * strokeLength); - } - return result; -} - -//! make a dashed QPainterPath from start to end in scene coords -QPainterPath QGIFace::dashedPPath(const std::vector dv, const Base::Vector3d start, const Base::Vector3d end) -{ - QPainterPath result; - Base::Vector3d dir = (end - start); - dir.Normalize(); - result.moveTo(start.x, -start.y); - Base::Vector3d currentPos = start; - if (dv.empty()) { - result.lineTo(end.x, -end.y); - m_segCount++; - } else { - double lineLength = (end - start).Length(); - double travel = 0.0; - Base::Vector3d lineProgress; - while (travel < lineLength) { - bool stop = false; - if (m_segCount > 10000) { - Base::Console().Warning("PAT segment count exceeded: %ld\n", m_segCount); - break; - } - - for (auto& d: dv) { - travel += fabs(d); - Base::Vector3d segmentEnd = (currentPos + dir * fabs(d)); - if ((start - segmentEnd).Length() > lineLength) { //don't draw past end of line - segmentEnd = end; - stop = true; - } - if (d < 0.0) { - result.moveTo(segmentEnd.x, -segmentEnd.y); //space - } else { - result.lineTo(segmentEnd.x, -segmentEnd.y); //mark - } - if (stop) { - break; - } - m_segCount++; - currentPos = segmentEnd; - } - } - } - return result; -} - -//! convert a dash pattern to an offset dash pattern (ie offset -> end) -// dv & offset are already scaled. -std::vector QGIFace::offsetDash(const std::vector dv, const double offset) -{ - std::vector result; - double length = 0.0; - for (auto& d: dv) { - length += fabs(d); - } - if (offset > length) { - result = dv; - return result; - } - //find the dash cell that includes offset - double accum = 0; - int i = 0; - for (auto& d:dv) { - accum += fabs(d); - if (accum > offset) { - break; - } - i++; - } - - double firstCell = accum - offset; - if (dv.at(i) < 0.0) { //offset found in a space cell - result.push_back(-1.0* firstCell); - } else { - result.push_back(firstCell); - } - unsigned int iCell = i + 1; - for ( ; iCell < dv.size() ; iCell++) { - result.push_back(dv.at(iCell)); - } - - return result; -} - -//! find remaining length of a dash pattern after offset -double QGIFace::dashRemain(const std::vector dv, const double offset) -{ - double length = 0.0; - for (auto& d: dv) { - length += fabs(d); - } - if (offset > length) { - return 0.0; - } - return length - offset; -} //! get zoom level (scale) from QGraphicsView // not used currently @@ -580,94 +358,6 @@ void QGIFace::clearSvg() hideSvg(true); } -/// make an array of bitmap tiles to cover this face -void QGIFace::buildPixHatch() -{ -// Base::Console().Message("QGIF::buildPixHatch() - offset: %s\n", DrawUtil::formatVector(getHatchOffset()).c_str()); - double wTile = SVGSIZEW * m_fillScale; - double hTile = SVGSIZEH * m_fillScale; - double faceWidth = m_outline.boundingRect().width(); - double faceHeight = m_outline.boundingRect().height(); - QRectF faceRect = m_outline.boundingRect(); - QPointF faceCenter = faceRect.center(); - double hatchOverlaySize = Preferences::svgHatchFactor() * std::max(faceWidth, faceHeight); - double numberWide = ceil(hatchOverlaySize / wTile); - double numberHigh = ceil(hatchOverlaySize / hTile); - double overlayWidth = numberWide * wTile; - double overlayHeight= numberHigh * hTile; - - m_svgHatchArea->setRect(0., 0., overlayWidth, -overlayHeight); - m_svgHatchArea->centerAt(faceCenter); - - QByteArray before, after; - before = QString::fromStdString(SVGCOLPREFIX + SVGCOLDEFAULT).toUtf8(); - after = QString::fromStdString(SVGCOLPREFIX + m_svgCol).toUtf8(); - QByteArray colorXML = m_svgXML.replace(before, after); - QSvgRenderer renderer; - bool success = renderer.load(colorXML); - if (!success) { - Base::Console().Error("QGIF::buildPixHatch - renderer failed to load\n"); - } - - //get the svg tile graphics as a QImage - QImage imageIn(64, 64, QImage::Format_ARGB32); - imageIn.fill(Qt::transparent); - QPainter painter(&imageIn); - renderer.render(&painter); - if (imageIn.isNull()) { - Base::Console().Error("QGIF::buildPixHatch - imageIn is null\n"); - return; - } - //make a QPixmap tile of the QImage - QPixmap pm(64, 64); - pm = QPixmap::fromImage(imageIn); - pm = pm.scaled(wTile, hTile); - if (pm.isNull()) { - Base::Console().Error("QGIF::buildPixHatch - pixmap is null\n"); - return; - } - - //layout a field of QPixmap tiles as a QImage - QImage tileField(overlayWidth, overlayHeight, QImage::Format_ARGB32); - QPointF fieldCenter(overlayWidth / 2.0, overlayHeight / 2.0); - - tileField.fill(Qt::transparent); - QPainter painter2(&tileField); - QPainter::RenderHints hints = painter2.renderHints(); - hints = hints & QPainter::Antialiasing; - painter2.setRenderHints(hints); - QPainterPath clipper = path(); - QPointF offset = (fieldCenter - faceCenter); - clipper.translate(offset); - painter2.setClipPath(clipper); - - long int tileCount = 0; - for (int iw = 0; iw < int(numberWide); iw++) { - for (int ih = 0; ih < int(numberHigh); ih++) { - painter2.drawPixmap(QRectF(iw*wTile + getHatchOffset().x, ih*hTile + getHatchOffset().y, - wTile, hTile), //target rect - pm, //map - QRectF(0, 0, wTile, hTile)); //source rect - tileCount++; - if (tileCount > m_maxTile) { - Base::Console().Warning("Pixmap tile count exceeded: %ld. Change hatch scale or raise limit.\n", tileCount); - break; - } - } - if (tileCount > m_maxTile) { - break; - } - } - - QPixmap bigMap(fabs(faceRect.width()), fabs(faceRect.height())); - bigMap = QPixmap::fromImage(tileField); - - QPixmap nothing; - m_imageHatchArea->setPixmap(nothing); - m_imageHatchArea->load(bigMap); - m_imageHatchArea->centerAt(faceCenter); -} - //this isn't used currently QPixmap QGIFace::textureFromSvg(std::string fileSpec) { @@ -698,6 +388,7 @@ void QGIFace::setHatchScale(double s) /// turn svg tiles on or off. QtSvg does not handle clipping, /// so we must be able to turn the hatching on/off when exporting a face with an /// svg hatch. Otherwise the full tile pattern is shown in the export. +/// NOTE: there appears to have been a change in Qt that it now clips svg items void QGIFace::hideSvg(bool b) { m_hideSvgTiles = b; diff --git a/src/Mod/TechDraw/Gui/QGIFace.h b/src/Mod/TechDraw/Gui/QGIFace.h index e3d3834af2..b451f0cc68 100644 --- a/src/Mod/TechDraw/Gui/QGIFace.h +++ b/src/Mod/TechDraw/Gui/QGIFace.h @@ -33,6 +33,7 @@ #include +#include "PATPathMaker.h" #include "QGIPrimPath.h" @@ -93,9 +94,6 @@ public: void hideSvg(bool b); void clearSvg(); - //tiled pixmap fill from svg - void buildPixHatch(); - //PAT fill parms & methods void setGeomHatchWeight(double w) { m_geomWeight = w; } void setLineWeight(double w); @@ -137,8 +135,6 @@ protected: std::string m_svgCol; std::string m_fileSpec; //for svg & bitmaps - QGCustomImage* m_imageHatchArea; - double m_fillScale; bool m_isHatched; QGIFace::fillMode m_mode; @@ -171,6 +167,8 @@ private: QSvgRenderer *m_sharedRender; + PATPathMaker* m_patMaker; + }; }