FreeCAD

Форк
0
/
QGIFace.cpp 
432 строки · 13.5 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2013 Luke Parry <l.parry@warwick.ac.uk>                 *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
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.      *
10
 *                                                                         *
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.                  *
15
 *                                                                         *
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                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24
#ifndef _PreComp_
25
# include <cmath>
26

27
# include <QFileInfo>
28
# include <QGraphicsView>
29
# include <QPainter>
30
# include <QPainterPath>
31
# include <QPointF>
32
# include <QRectF>
33
# include <QTransform>
34
#endif
35

36
#include <App/Application.h>
37
#include <Base/Console.h>
38
#include <Base/Parameter.h>
39
#include <Mod/TechDraw/App/DrawUtil.h>
40

41
#include "PreferencesGui.h"
42
#include "QGIFace.h"
43
#include <QByteArrayMatcher>
44
#include "QGCustomRect.h"
45
#include "QGCustomSvg.h"
46
#include "QGICMark.h"
47
#include "QGIPrimPath.h"
48
#include "Rez.h"
49
#include "ZVALUE.h"
50

51
using namespace TechDrawGui;
52
using namespace TechDraw;
53

54
QGIFace::QGIFace(int index) :
55
    projIndex(index),
56
    m_hideSvgTiles(false),
57
    m_hatchRotation(0.0)
58
{
59
    m_segCount = 0;
60
//    setFillMode(NoFill);
61
    isHatched(false);
62
    setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
63

64
    setStyle(Qt::NoPen);    //don't draw face lines, just fill for debugging
65
    //setStyle(Qt::DashLine);
66
    m_geomColor = PreferencesGui::getAccessibleQColor(QColor(Qt::black));
67
    m_styleCurrent = Qt::NoPen;
68
    m_pen.setStyle(m_styleCurrent);
69
    setLineWeight(0.0);                   //0 = cosmetic
70

71
    setPrettyNormal();
72
    m_texture = QPixmap();                      //empty texture
73

74
    m_svgHatchArea = new QGCustomRect();
75
    m_svgHatchArea->setParentItem(this);
76

77
    m_svgCol = SVGCOLDEFAULT;
78
    m_fillScale = 1.0;
79

80
    getParameters();
81

82
    // set up style & colour defaults
83
    m_colDefFill = App::Color(static_cast<uint32_t>(Preferences::getPreferenceGroup("Colors")->GetUnsigned("FaceColor", 0xFFFFFF)))
84
                   .asValue<QColor>();
85
    m_colDefFill.setAlpha(Preferences::getPreferenceGroup("Colors")->GetBool("ClearFace", false) ? 0 : 255);
86

87
    m_fillDef = Qt::SolidPattern;
88
    m_fillSelect = Qt::SolidPattern;
89

90
    setFillMode(m_colDefFill.alpha() ? PlainFill : NoFill);
91
    setFill(m_colDefFill, m_fillDef);
92

93
    m_sharedRender = new QSvgRenderer();
94
    m_patMaker = new PATPathMaker(this, 1.0, 1.0);
95
}
96

97
QGIFace::~QGIFace()
98
{
99
    delete m_sharedRender;
100
    delete m_patMaker;
101
}
102

103
/// redraw this face
104
void QGIFace::draw()
105
{
106
//    Base::Console().Message("QGIF::draw - pen style: %d\n", m_pen.style());
107
    setPath(m_outline);                         //Face boundary
108

109
    if (isHatched()) {
110
        if (m_mode == GeomHatchFill) {
111
            //GeomHatch does not appear in pdf if clipping is set to true
112
            setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
113
            if (!m_lineSets.empty()) {
114
                m_brush.setTexture(QPixmap());
115
                m_fillStyleCurrent = m_fillDef;
116
                m_fillNormal = m_fillStyleCurrent;
117
                for (auto& ls: m_lineSets) {
118
                    lineSetToFillItems(ls);
119
                }
120
            }
121
            m_svgHatchArea->hide();
122
        } else if (m_mode == SvgFill) {
123
            m_brush.setTexture(QPixmap());
124
            m_fillNormal = m_fillDef;
125
            m_fillStyleCurrent = m_fillNormal;
126
            loadSvgHatch(m_fileSpec);
127
            //SVG tiles need to be clipped
128
            setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
129
            buildSvgHatch();
130
            m_svgHatchArea->show();
131
        } else if (m_mode == BitmapFill) {
132
            m_fillStyleCurrent = Qt::TexturePattern;
133
            m_texture = textureFromBitmap(m_fileSpec);
134
            m_brush.setTexture(m_texture);
135
            m_svgHatchArea->hide();
136
        } else if (m_mode == PlainFill) {
137
            setFill(m_colNormalFill, m_fillNormal);
138
            m_svgHatchArea->hide();
139
        }
140
    } else {
141
        // face is not hatched
142
        m_svgHatchArea->hide();
143
    }
144
    show();
145
}
146

147
/// show the face style & colour in normal configuration
148
void QGIFace::setPrettyNormal() {
149
//    Base::Console().Message("QGIF::setPrettyNormal() - hatched: %d\n", isHatched());
150
    if (isHatched()  &&
151
        (m_mode == BitmapFill) ) {                               //hatch with bitmap fill
152
        m_fillStyleCurrent = Qt::TexturePattern;
153
        m_brush.setTexture(m_texture);
154
    } else {
155
        m_brush.setTexture(QPixmap());
156
    }
157
    QGIPrimPath::setPrettyNormal();
158
}
159

160
/// show the face style & colour in pre-select configuration
161
void QGIFace::setPrettyPre() {
162
//    Base::Console().Message("QGIF::setPrettyPre()\n");
163
    m_fillStyleCurrent = Qt::SolidPattern;
164
    m_brush.setTexture(QPixmap());
165
    QGIPrimPath::setPrettyPre();
166
}
167

168
/// show the face style & colour in selected configuration
169
void QGIFace::setPrettySel() {
170
//    Base::Console().Message("QGIF::setPrettySel()\n");
171
    m_fillStyleCurrent = Qt::SolidPattern;
172
    m_brush.setTexture(QPixmap());
173
    QGIPrimPath::setPrettySel();
174
}
175

176
/// show or hide the edges of this face.  Usually just for debugging
177
void QGIFace::setDrawEdges(bool b) {
178
//    Base::Console().Message("QGIF::setDrawEdges(%d)\n", b);
179
    if (b) {
180
        setStyle(Qt::DashLine);
181
    } else {
182
        setStyle(Qt::NoPen);    //don't draw face lines, just fill
183
    }
184
}
185

186
void QGIFace::setHatchFile(std::string fileSpec)
187
{
188
    m_fileSpec = fileSpec;
189
}
190

191
/// get the .svg file to use for hatching this face
192
void QGIFace::loadSvgHatch(std::string fileSpec)
193
{
194
    QString qfs(QString::fromUtf8(fileSpec.data(), fileSpec.size()));
195
    QFile f(qfs);
196
    if (!f.open(QFile::ReadOnly | QFile::Text))  {
197
        Base::Console().Error("QGIFace could not read %s\n", fileSpec.c_str());
198
        return;
199
    }
200
    m_svgXML = f.readAll();
201

202
    // search in the file for the "stroke" specification in order to find out what declaration style is used
203
    // this is necessary to apply a color set by the user to the SVG
204
    QByteArray pattern("stroke:");
205
    QByteArrayMatcher matcher(pattern);
206
    int pos = 0;
207
    if (matcher.indexIn(m_svgXML, pos) != -1) {
208
        SVGCOLPREFIX = "stroke:"; // declaration part of a style="" statement
209
    } else {
210
        SVGCOLPREFIX = "stroke=\""; // declaration of its own
211
    }
212
}
213

214
void QGIFace::setFillMode(QGIFace::fillMode m)
215
{
216
    m_mode = m;
217
    if ((m_mode == NoFill) ||
218
        (m_mode == PlainFill)) {
219
        isHatched(false);
220
    } else {
221
        isHatched(true);
222
    }
223
}
224

225
/// update the outline of this face
226
void QGIFace::setOutline(const QPainterPath & path)
227
{
228
    m_outline = path;
229
}
230

231
/// remove the PAT hatch lines
232
void QGIFace::clearLineSets()
233
{
234
    m_dashSpecs.clear();
235
    clearFillItems();
236
}
237

238
/// add PAT hatch line set
239
void QGIFace::addLineSet(LineSet& ls)
240
{
241
    m_lineSets.push_back(ls);
242
}
243

244
/// convert the PAT line set to QGraphicsPathItems
245
void QGIFace::lineSetToFillItems(LineSet& ls)
246
{
247
    m_patMaker->setLineWidth(Rez::guiX(m_geomWeight));
248
    m_patMaker->setScale(m_fillScale);
249
    m_patMaker->setPen(setGeomPen());
250
    m_patMaker->lineSetToFillItems(ls);
251
}
252

253
QPen QGIFace::setGeomPen()
254
{
255
    QPen result;
256
    result.setWidthF(Rez::guiX(m_geomWeight));
257
    result.setColor(m_geomColor);
258
    result.setStyle(Qt::SolidLine);
259
    return result;
260
}
261

262

263
//! get zoom level (scale) from QGraphicsView
264
// not used currently
265
double QGIFace::getXForm()
266
{
267
    //try to keep the pattern the same when View scales
268
    auto s = scene();
269
    if (s) {
270
        auto vs = s->views();     //ptrs to views
271
        if (!vs.empty()) {
272
            auto v = vs.at(0);
273
            auto i = v->transform().inverted();
274
            return i.m11();
275
        }
276
    }
277
    return 1.0;
278
}
279

280
/// remove the children that make up a PAT fill
281
void QGIFace::clearFillItems()
282
{
283
    for (auto& f: m_fillItems) {
284
        f->setParentItem(nullptr);
285
        this->scene()->removeItem(f);
286
        delete f;
287
    }
288
}
289

290
/// debugging tool draws a mark at a position on this face
291
void QGIFace::makeMark(double x, double y)
292
{
293
    QGICMark* cmItem = new QGICMark(-1);
294
    cmItem->setParentItem(this);
295
    cmItem->setPos(x, y);
296
    cmItem->setThick(1.0);
297
    cmItem->setSize(40.0);
298
    cmItem->setZValue(ZVALUE::VERTEX);
299
}
300

301
/// make an array of svg tiles to cover this face
302
void QGIFace::buildSvgHatch()
303
{
304
//    Base::Console().Message("QGIF::buildSvgHatch() - offset: %s\n", DrawUtil::formatVector(getHatchOffset()).c_str());
305
    double wTile = SVGSIZEW * m_fillScale;
306
    double hTile = SVGSIZEH * m_fillScale;
307
    double faceWidth = m_outline.boundingRect().width();
308
    double faceHeight = m_outline.boundingRect().height();
309
    double faceOverlaySize = Preferences::svgHatchFactor() * std::max(faceWidth, faceHeight);
310
    QPointF faceCenter = m_outline.boundingRect().center();
311
    double tilesWide = ceil(faceOverlaySize / wTile);
312
    double tilesHigh = ceil(faceOverlaySize / hTile);
313

314
    double overlayWidth = tilesWide * wTile;
315
    double overlayHeight = tilesHigh * hTile;
316
    m_svgHatchArea->setRect(0., 0., overlayWidth,-overlayHeight);
317
    m_svgHatchArea->centerAt(faceCenter);
318
    QByteArray before, after;
319
    before = QString::fromStdString(SVGCOLPREFIX + SVGCOLDEFAULT).toUtf8();
320
    after = QString::fromStdString(SVGCOLPREFIX + m_svgCol).toUtf8();
321
    QByteArray colorXML = m_svgXML.replace(before, after);
322
    if (!m_sharedRender->load(colorXML)) {
323
        Base::Console().Message("QGIF::buildSvgHatch - failed to load svg string\n");
324
        return;
325
    }
326
    long int tileCount = 0;
327
    for (int iw = 0; iw < int(tilesWide); iw++) {
328
        for (int ih = 0; ih < int(tilesHigh); ih++) {
329
            QGCustomSvg* tile = new QGCustomSvg();
330
            tile->setScale(m_fillScale);
331
            tile->setSharedRenderer(m_sharedRender);
332
            tile->setParentItem(m_svgHatchArea);
333
            tile->setPos(iw*wTile + getHatchOffset().x,
334
                         -overlayWidth + ih*hTile + getHatchOffset().y);
335
            tileCount++;
336
            if (tileCount > m_maxTile) {
337
                Base::Console().Warning("SVG tile count exceeded: %ld. Change hatch scale or raise limit.\n", tileCount);
338
                break;
339
            }
340
        }
341
        if (tileCount > m_maxTile) {
342
            break;
343
        }
344
    }
345
    QPointF faceCenterToMRect = mapToItem(m_svgHatchArea, faceCenter);
346
    m_svgHatchArea->setTransformOriginPoint(faceCenterToMRect);
347
    m_svgHatchArea->setRotation(m_hatchRotation);
348
}
349

350
void QGIFace::clearSvg()
351
{
352
    hideSvg(true);
353
}
354

355
//this isn't used currently
356
QPixmap QGIFace::textureFromSvg(std::string fileSpec)
357
{
358
    QString qs(QString::fromStdString(fileSpec));
359
    QFileInfo ffi(qs);
360
    if (!ffi.isReadable()) {
361
        return QPixmap();
362
    }
363
    QSvgRenderer renderer(qs);
364
    QPixmap pixMap(renderer.defaultSize());
365
    pixMap.fill(Qt::white);                                            //try  Qt::transparent?
366
    QPainter painter(&pixMap);
367
    renderer.render(&painter);                                         //svg texture -> bitmap
368
    return pixMap.scaled(m_fillScale, m_fillScale);
369
}
370

371
void QGIFace::setHatchColor(App::Color c)
372
{
373
    m_svgCol = c.asHexString();
374
    m_geomColor = c.asValue<QColor>();
375
}
376

377
void QGIFace::setHatchScale(double s)
378
{
379
    m_fillScale = s;
380
}
381

382
/// turn svg tiles on or off. QtSvg does not handle clipping,
383
/// so we must be able to turn the hatching on/off when exporting a face with an
384
/// svg hatch.  Otherwise the full tile pattern is shown in the export.
385
/// NOTE: there appears to have been a change in Qt that it now clips svg items
386
void QGIFace::hideSvg(bool b)
387
{
388
    m_hideSvgTiles = b;
389
}
390

391

392
/// create a QPixmap from a bitmap file.  The QPixmap will be used as a QBrush
393
/// texture.
394
QPixmap QGIFace::textureFromBitmap(std::string fileSpec)
395
{
396
    QPixmap pix;
397

398
    QString qfs(QString::fromUtf8(fileSpec.data(), fileSpec.size()));
399
    QFile f(qfs);
400
    if (!f.open(QFile::ReadOnly))  {
401
        Base::Console().Error("QGIFace could not read %s\n", fileSpec.c_str());
402
        return pix;
403
    }
404
    QByteArray bytes = f.readAll();
405
    pix.loadFromData(bytes);
406
    if (m_hatchRotation != 0.0) {
407
        QTransform rotator;
408
        rotator.rotate(m_hatchRotation);
409
        pix = pix.transformed(rotator);
410
    }
411
    return pix;
412
}
413

414
void QGIFace::setLineWeight(double w) {
415
    m_geomWeight = w;
416
}
417

418
void QGIFace::getParameters()
419
{
420
    m_maxSeg = Preferences::getPreferenceGroup("PAT")->GetInt("MaxSeg", 10000l);
421
    m_maxTile = Preferences::getPreferenceGroup("Decorations")->GetInt("MaxSVGTile", 10000l);
422
}
423

424
QRectF QGIFace::boundingRect() const
425
{
426
    return shape().controlPointRect();
427
}
428

429
QPainterPath QGIFace::shape() const
430
{
431
    return path();
432
}
433

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.