~ubuntu-branches/ubuntu/trusty/fritzing/trusty-proposed

« back to all changes in this revision

Viewing changes to .pc/armel.patch/src/svg/gerbergenerator.cpp

  • Committer: Package Import Robot
  • Author(s): Georges Khaznadar
  • Date: 2012-06-13 19:41:31 UTC
  • Revision ID: package-import@ubuntu.com-20120613194131-zun1a3n3lltnkehn
Tags: 0.7.4b+dfsg-2
applied Jonathan Cohen's patch, which should fix the compilation
issue for armel.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*******************************************************************
 
2
 
 
3
Part of the Fritzing project - http://fritzing.org
 
4
Copyright (c) 2007-2011 Fachhochschule Potsdam - http://fh-potsdam.de
 
5
 
 
6
Fritzing is free software: you can redistribute it and/or modify
 
7
it under the terms of the GNU General Public License as published by
 
8
the Free Software Foundation, either version 3 of the License, or
 
9
(at your option) any later version.
 
10
 
 
11
Fritzing 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 General Public License for more details.
 
15
 
 
16
You should have received a copy of the GNU General Public License
 
17
along with Fritzing.  If not, see <http://www.gnu.org/licenses/>.
 
18
 
 
19
********************************************************************
 
20
 
 
21
$Revision: 5930 $:
 
22
$Author: cohen@irascible.com $:
 
23
$Date: 2012-03-28 13:26:38 +0200 (Wed, 28 Mar 2012) $
 
24
 
 
25
********************************************************************/
 
26
 
 
27
#include <QMessageBox>
 
28
#include <QFileDialog>
 
29
#include <QSvgRenderer>
 
30
#include <qmath.h>
 
31
 
 
32
#include "gerbergenerator.h"
 
33
#include "../debugdialog.h"
 
34
#include "../fsvgrenderer.h"
 
35
#include "../sketch/pcbsketchwidget.h"
 
36
#include "svgfilesplitter.h"
 
37
#include "groundplanegenerator.h"
 
38
#include "../utils/graphicsutils.h"
 
39
#include "../utils/textutils.h"
 
40
#include "../utils/folderutils.h"
 
41
 
 
42
static QRegExp AaCc("[aAcCqQtTsS]");
 
43
 
 
44
const QString GerberGenerator::SilkTopSuffix = "_silkTop.gto";
 
45
const QString GerberGenerator::SilkBottomSuffix = "_silkBottom.gbo";
 
46
const QString GerberGenerator::CopperTopSuffix = "_copperTop.gtl";
 
47
const QString GerberGenerator::CopperBottomSuffix = "_copperBottom.gbl";
 
48
const QString GerberGenerator::MaskTopSuffix = "_maskTop.gts";
 
49
const QString GerberGenerator::MaskBottomSuffix = "_maskBottom.gbs";
 
50
const QString GerberGenerator::DrillSuffix = "_drill.txt";
 
51
const QString GerberGenerator::OutlineSuffix = "_contour.gm1";
 
52
const QString GerberGenerator::MagicBoardOutlineID = "boardoutline";
 
53
 
 
54
const double GerberGenerator::MaskClearanceMils = 3;    
 
55
 
 
56
////////////////////////////////////////////
 
57
 
 
58
bool pixelsCollide(QImage * image1, QImage * image2, int x1, int y1, int x2, int y2) {
 
59
        for (int y = y1; y < y2; y++) {
 
60
                for (int x = x1; x < x2; x++) {
 
61
                        QRgb p1 = image1->pixel(x, y);
 
62
                        if (p1 == 0xffffffff) continue;
 
63
 
 
64
                        QRgb p2 = image2->pixel(x, y);
 
65
                        if (p2 == 0xffffffff) continue;
 
66
 
 
67
                        //DebugDialog::debug(QString("p1:%1 p2:%2").arg(p1, 0, 16).arg(p2, 0, 16));
 
68
 
 
69
                        return true;
 
70
                }
 
71
        }
 
72
 
 
73
        return false;
 
74
}
 
75
 
 
76
////////////////////////////////////////////
 
77
 
 
78
void GerberGenerator::exportToGerber(const QString & filename, const QString & exportDir, ItemBase * board, PCBSketchWidget * sketchWidget, bool displayMessageBoxes) 
 
79
{
 
80
        if (board == NULL) {
 
81
                QList<ItemBase *> boards = sketchWidget->findBoard();
 
82
                if (boards.count() == 0) {
 
83
                        DebugDialog::debug("board not found");
 
84
                        return;
 
85
                }
 
86
                if (boards.count() > 1) {
 
87
                        DebugDialog::debug("multiple boards found");
 
88
                        return;
 
89
                }
 
90
 
 
91
                board = boards.at(0);
 
92
        }
 
93
 
 
94
        LayerList viewLayerIDs = ViewLayer::copperLayers(ViewLayer::Bottom);
 
95
        int copperInvalidCount = doCopper(board, sketchWidget, viewLayerIDs, "Copper0", CopperBottomSuffix, filename, exportDir, displayMessageBoxes);
 
96
 
 
97
        if (sketchWidget->boardLayers() == 2) {
 
98
                viewLayerIDs = ViewLayer::copperLayers(ViewLayer::Top);
 
99
                copperInvalidCount += doCopper(board, sketchWidget, viewLayerIDs, "Copper1", CopperTopSuffix, filename, exportDir, displayMessageBoxes);
 
100
        }
 
101
 
 
102
        LayerList maskLayerIDs = ViewLayer::maskLayers(ViewLayer::Bottom);
 
103
        QString maskBottom, maskTop;
 
104
        int maskInvalidCount = doMask(maskLayerIDs, "Mask0", MaskBottomSuffix, board, sketchWidget, filename, exportDir, displayMessageBoxes, maskBottom);
 
105
 
 
106
        if (sketchWidget->boardLayers() == 2) {
 
107
                maskLayerIDs = ViewLayer::maskLayers(ViewLayer::Top);
 
108
                maskInvalidCount += doMask(maskLayerIDs, "Mask1", MaskTopSuffix, board, sketchWidget, filename, exportDir, displayMessageBoxes, maskTop);
 
109
        }
 
110
 
 
111
    LayerList silkLayerIDs = ViewLayer::silkLayers(ViewLayer::Top);
 
112
        int silkInvalidCount = doSilk(silkLayerIDs, "Silk1", SilkTopSuffix, board, sketchWidget, filename, exportDir, displayMessageBoxes, maskTop);
 
113
    silkLayerIDs = ViewLayer::silkLayers(ViewLayer::Bottom);
 
114
        silkInvalidCount += doSilk(silkLayerIDs, "Silk0", SilkBottomSuffix, board, sketchWidget, filename, exportDir, displayMessageBoxes, maskBottom);
 
115
 
 
116
    // now do it for the outline/contour
 
117
    LayerList outlineLayerIDs = ViewLayer::outlineLayers();
 
118
        QSizeF imageSize;
 
119
        bool empty;
 
120
        QString svgOutline = sketchWidget->renderToSVG(FSvgRenderer::printerScale(), outlineLayerIDs, true, imageSize, board, GraphicsUtils::StandardFritzingDPI, false, false, false, empty);
 
121
    if (svgOutline.isEmpty()) {
 
122
        displayMessage(QObject::tr("outline is empty"), displayMessageBoxes);
 
123
        return;
 
124
    }
 
125
 
 
126
        svgOutline = cleanOutline(svgOutline);
 
127
        svgOutline = clipToBoard(svgOutline, board, "board", SVG2gerber::ForOutline, "");
 
128
 
 
129
        QXmlStreamReader streamReader(svgOutline);
 
130
        QSizeF svgSize = FSvgRenderer::parseForWidthAndHeight(streamReader);
 
131
 
 
132
    // create outline gerber from svg
 
133
    SVG2gerber outlineGerber;
 
134
        int outlineInvalidCount = outlineGerber.convert(svgOutline, sketchWidget->boardLayers() == 2, "contour", SVG2gerber::ForOutline, svgSize * GraphicsUtils::StandardFritzingDPI);
 
135
        
 
136
        //DebugDialog::debug(QString("outline output: %1").arg(outlineGerber.getGerber()));
 
137
        saveEnd("contour", exportDir, filename, OutlineSuffix, displayMessageBoxes, true, outlineGerber);
 
138
 
 
139
        doDrill(board, sketchWidget, filename, exportDir, displayMessageBoxes);
 
140
 
 
141
        if (outlineInvalidCount > 0 || silkInvalidCount > 0 || copperInvalidCount > 0 || maskInvalidCount) {
 
142
                QString s;
 
143
                if (outlineInvalidCount > 0) s += QObject::tr("the board outline layer, ");
 
144
                if (silkInvalidCount > 0) s += QObject::tr("silkscreen layer(s), ");
 
145
                if (copperInvalidCount > 0) s += QObject::tr("copper layer(s), ");
 
146
                if (maskInvalidCount > 0) s += QObject::tr("mask layer(s), ");
 
147
                s.chop(2);
 
148
                displayMessage(QObject::tr("Unable to translate svg curves in %1").arg(s), displayMessageBoxes);
 
149
        }
 
150
 
 
151
}
 
152
 
 
153
int GerberGenerator::doCopper(ItemBase * board, PCBSketchWidget * sketchWidget, LayerList & viewLayerIDs, const QString & copperName, const QString & copperSuffix, const QString & filename, const QString & exportDir, bool displayMessageBoxes) 
 
154
{
 
155
        QSizeF imageSize;
 
156
        bool empty;
 
157
        QString svg = sketchWidget->renderToSVG(FSvgRenderer::printerScale(), viewLayerIDs, true, imageSize, board, GraphicsUtils::StandardFritzingDPI, false, false, false, empty);
 
158
        if (svg.isEmpty()) {
 
159
                displayMessage(QObject::tr("%1 file export failure (1)").arg(copperName), displayMessageBoxes);
 
160
                return 0;
 
161
        }
 
162
 
 
163
        QXmlStreamReader streamReader(svg);
 
164
        QSizeF svgSize = FSvgRenderer::parseForWidthAndHeight(streamReader);
 
165
 
 
166
        svg = clipToBoard(svg, board, copperName, SVG2gerber::ForCopper, "");
 
167
        if (svg.isEmpty()) {
 
168
                displayMessage(QObject::tr("%1 file export failure (3)").arg(copperName), displayMessageBoxes);
 
169
                return 0;
 
170
        }
 
171
 
 
172
        return doEnd(svg, sketchWidget->boardLayers(), copperName, SVG2gerber::ForCopper, svgSize * GraphicsUtils::StandardFritzingDPI, exportDir, filename, copperSuffix, displayMessageBoxes, true);
 
173
}
 
174
 
 
175
 
 
176
int GerberGenerator::doSilk(LayerList silkLayerIDs, const QString & silkName, const QString & gerberSuffix, ItemBase * board, PCBSketchWidget * sketchWidget, const QString & filename, const QString & exportDir, bool displayMessageBoxes, const QString & clipString) 
 
177
{
 
178
        QSizeF imageSize;
 
179
        bool empty;
 
180
        QString svgSilk = sketchWidget->renderToSVG(FSvgRenderer::printerScale(), silkLayerIDs, true, imageSize, board, GraphicsUtils::StandardFritzingDPI, false, false, false, empty);
 
181
    if (svgSilk.isEmpty()) {
 
182
                displayMessage(QObject::tr("silk file export failure (1)"), displayMessageBoxes);
 
183
        return 0;
 
184
    }
 
185
 
 
186
        if (empty) {
 
187
                // don't bother with file
 
188
                return 0;
 
189
        }
 
190
 
 
191
        //QFile f(silkName + "original.svg");
 
192
        //f.open(QFile::WriteOnly);
 
193
        //QTextStream fs(&f);
 
194
        //fs << svgSilk;
 
195
        //f.close();
 
196
 
 
197
        QXmlStreamReader streamReader(svgSilk);
 
198
        QSizeF svgSize = FSvgRenderer::parseForWidthAndHeight(streamReader);
 
199
 
 
200
        svgSilk = clipToBoard(svgSilk, board, silkName, SVG2gerber::ForSilk, clipString);
 
201
        if (svgSilk.isEmpty()) {
 
202
                displayMessage(QObject::tr("silk export failure"), displayMessageBoxes);
 
203
                return 0;
 
204
        }
 
205
 
 
206
        //QFile f2(silkName + "clipped.svg");
 
207
        //f2.open(QFile::WriteOnly);
 
208
        //QTextStream fs2(&f2);
 
209
        //fs2 << svgSilk;
 
210
        //f2.close();
 
211
 
 
212
        return doEnd(svgSilk, sketchWidget->boardLayers(), silkName, SVG2gerber::ForSilk, svgSize * GraphicsUtils::StandardFritzingDPI, exportDir, filename, gerberSuffix, displayMessageBoxes, true);
 
213
}
 
214
 
 
215
 
 
216
int GerberGenerator::doDrill(ItemBase * board, PCBSketchWidget * sketchWidget, const QString & filename, const QString & exportDir, bool displayMessageBoxes) 
 
217
{
 
218
    LayerList drillLayerIDs;
 
219
    drillLayerIDs << ViewLayer::drillLayers();
 
220
 
 
221
        QSizeF imageSize;
 
222
        bool empty;
 
223
        QString svgDrill = sketchWidget->renderToSVG(FSvgRenderer::printerScale(), drillLayerIDs, true, imageSize, board, GraphicsUtils::StandardFritzingDPI, false, false, false, empty);
 
224
    if (svgDrill.isEmpty()) {
 
225
                displayMessage(QObject::tr("drill file export failure (1)"), displayMessageBoxes);
 
226
        return 0;
 
227
    }
 
228
 
 
229
        if (empty) {
 
230
                // don't bother with file
 
231
                return 0;
 
232
        }
 
233
 
 
234
        QXmlStreamReader streamReader(svgDrill);
 
235
        QSizeF svgSize = FSvgRenderer::parseForWidthAndHeight(streamReader);
 
236
 
 
237
        svgDrill = clipToBoard(svgDrill, board, "Copper0", SVG2gerber::ForDrill, "");
 
238
        if (svgDrill.isEmpty()) {
 
239
                displayMessage(QObject::tr("drill export failure"), displayMessageBoxes);
 
240
                return 0;
 
241
        }
 
242
 
 
243
        return doEnd(svgDrill, sketchWidget->boardLayers(), "drill", SVG2gerber::ForDrill, svgSize * GraphicsUtils::StandardFritzingDPI, exportDir, filename, DrillSuffix, displayMessageBoxes, true);
 
244
}
 
245
 
 
246
int GerberGenerator::doMask(LayerList maskLayerIDs, const QString &maskName, const QString & gerberSuffix, ItemBase * board, PCBSketchWidget * sketchWidget, const QString & filename, const QString & exportDir, bool displayMessageBoxes, QString & clipString) 
 
247
{
 
248
        // don't want these in the mask laqyer
 
249
        QList<ItemBase *> copperLogoItems;
 
250
        sketchWidget->hideCopperLogoItems(copperLogoItems);
 
251
 
 
252
        QSizeF imageSize;
 
253
        bool empty;
 
254
        QString svgMask = sketchWidget->renderToSVG(FSvgRenderer::printerScale(), maskLayerIDs, true, imageSize, board, GraphicsUtils::StandardFritzingDPI, false, false, false, empty);
 
255
    if (svgMask.isEmpty()) {
 
256
                displayMessage(QObject::tr("mask file export failure (1)"), displayMessageBoxes);
 
257
        return 0;
 
258
    }
 
259
 
 
260
        sketchWidget->restoreCopperLogoItems(copperLogoItems);
 
261
 
 
262
        if (empty) {
 
263
                // don't bother with file
 
264
                return 0;
 
265
        }
 
266
 
 
267
        svgMask = TextUtils::expandAndFill(svgMask, "black", MaskClearanceMils * 2);
 
268
        if (svgMask.isEmpty()) {
 
269
                displayMessage(QObject::tr("%1 mask export failure (2)").arg(maskName), displayMessageBoxes);
 
270
                return 0;
 
271
        }
 
272
 
 
273
        QXmlStreamReader streamReader(svgMask);
 
274
        QSizeF svgSize = FSvgRenderer::parseForWidthAndHeight(streamReader);
 
275
 
 
276
        svgMask = clipToBoard(svgMask, board, maskName, SVG2gerber::ForCopper, "");
 
277
        if (svgMask.isEmpty()) {
 
278
                displayMessage(QObject::tr("mask export failure"), displayMessageBoxes);
 
279
                return 0;
 
280
        }
 
281
 
 
282
        clipString = svgMask;
 
283
 
 
284
        return doEnd(svgMask, sketchWidget->boardLayers(), maskName, SVG2gerber::ForCopper, svgSize * GraphicsUtils::StandardFritzingDPI, exportDir, filename, gerberSuffix, displayMessageBoxes, true);
 
285
}
 
286
 
 
287
int GerberGenerator::doEnd(const QString & svg, int boardLayers, const QString & layerName, SVG2gerber::ForWhy forWhy, QSizeF svgSize, 
 
288
                                                        const QString & exportDir, const QString & prefix, const QString & suffix, bool displayMessageBoxes, bool chopPrefix)
 
289
{
 
290
    // create mask gerber from svg
 
291
    SVG2gerber gerber;
 
292
        int invalidCount = gerber.convert(svg, boardLayers == 2, layerName, forWhy, svgSize);
 
293
 
 
294
        saveEnd(layerName, exportDir, prefix, suffix, displayMessageBoxes, chopPrefix, gerber);
 
295
 
 
296
        return invalidCount;
 
297
}
 
298
 
 
299
bool GerberGenerator::saveEnd(const QString & layerName, const QString & exportDir, const QString & prefix, const QString & suffix, bool displayMessageBoxes, bool chopPrefix, SVG2gerber & gerber)
 
300
{
 
301
        QString usePrefix = (chopPrefix) ? QFileInfo(prefix).completeBaseName() : prefix;
 
302
 
 
303
    QString outname = exportDir + "/" +  usePrefix + suffix;
 
304
    QFile out(outname);
 
305
        if (!out.open(QIODevice::WriteOnly | QIODevice::Text)) {
 
306
                displayMessage(QObject::tr("%1 file export failure (2)").arg(layerName), displayMessageBoxes);
 
307
                return false;
 
308
        }
 
309
 
 
310
    QTextStream stream(&out);
 
311
    stream << gerber.getGerber();
 
312
        stream.flush();
 
313
        out.close();
 
314
        return true;
 
315
 
 
316
}
 
317
 
 
318
void GerberGenerator::displayMessage(const QString & message, bool displayMessageBoxes) {
 
319
        // don't use QMessageBox if running conversion as a service
 
320
        if (displayMessageBoxes) {
 
321
                QMessageBox::warning(NULL, QObject::tr("Fritzing"), message);
 
322
                return;
 
323
        }
 
324
 
 
325
        DebugDialog::debug(message);
 
326
}
 
327
 
 
328
QString GerberGenerator::clipToBoard(QString svgString, ItemBase * board, const QString & layerName, SVG2gerber::ForWhy forWhy, const QString & clipString) {
 
329
        QRectF source = board->sceneBoundingRect();
 
330
        source.moveTo(0, 0);
 
331
        return clipToBoard(svgString, source, layerName, forWhy, clipString);
 
332
}
 
333
 
 
334
QString GerberGenerator::clipToBoard(QString svgString, QRectF & boardRect, const QString & layerName, SVG2gerber::ForWhy forWhy, const QString & clipString) {
 
335
        // document 1 will contain svg that is easy to convert to gerber
 
336
        QDomDocument domDocument1;
 
337
        QString errorStr;
 
338
        int errorLine;
 
339
        int errorColumn;
 
340
        bool result = domDocument1.setContent(svgString, &errorStr, &errorLine, &errorColumn);
 
341
        if (!result) {
 
342
                return "";
 
343
        }
 
344
 
 
345
        QDomElement root = domDocument1.documentElement();
 
346
        if (root.firstChildElement().isNull()) {
 
347
                return "";
 
348
        }
 
349
 
 
350
        // document 2 will contain svg that must be rasterized for gerber conversion
 
351
        QDomDocument domDocument2;
 
352
        domDocument2.setContent(svgString, &errorStr, &errorLine, &errorColumn);
 
353
 
 
354
        bool anyConverted = false;
 
355
    if (TextUtils::squashElement(domDocument1, "text", "", QRegExp())) {
 
356
        anyConverted = true; 
 
357
        }
 
358
 
 
359
        // gerber can't handle ellipses that are rotated, so cull them all
 
360
    if (TextUtils::squashElement(domDocument1, "ellipse", "", QRegExp())) {
 
361
                anyConverted = true;
 
362
    }
 
363
 
 
364
    if (TextUtils::squashElement(domDocument1, "rect", "rx", QRegExp())) {
 
365
                anyConverted = true;
 
366
    }
 
367
 
 
368
    if (TextUtils::squashElement(domDocument1, "rect", "ry", QRegExp())) {
 
369
                anyConverted = true;
 
370
    }
 
371
 
 
372
        // gerber can't handle paths with curves
 
373
    if (TextUtils::squashElement(domDocument1, "path", "d", AaCc)) {
 
374
                anyConverted = true;
 
375
    }
 
376
 
 
377
        QVector <QDomElement> leaves1;
 
378
        int transformCount1 = 0;
 
379
    QDomElement e1 = domDocument1.documentElement();
 
380
    TextUtils::collectLeaves(e1, transformCount1, leaves1);
 
381
 
 
382
        QVector <QDomElement> leaves2;
 
383
        int transformCount2 = 0;
 
384
    QDomElement e2 = domDocument2.documentElement();
 
385
    TextUtils::collectLeaves(e2, transformCount2, leaves2);
 
386
 
 
387
        double res = GraphicsUtils::StandardFritzingDPI;
 
388
        // convert from pixel dpi to StandardFritzingDPI
 
389
        QRectF sourceRes(boardRect.left() * res / FSvgRenderer::printerScale(), boardRect.top() * res / FSvgRenderer::printerScale(), 
 
390
                                         boardRect.width() * res / FSvgRenderer::printerScale(), boardRect.height() * res / FSvgRenderer::printerScale());
 
391
        int twidth = sourceRes.width();
 
392
        int theight = sourceRes.height();
 
393
        QSize imgSize(twidth, theight);
 
394
 
 
395
        QImage * clipImage = NULL;
 
396
        if (!clipString.isEmpty()) {
 
397
                clipImage = new QImage(imgSize, QImage::Format_Mono);
 
398
                clipImage->fill(0xffffffff);
 
399
                clipImage->setDotsPerMeterX(res * GraphicsUtils::InchesPerMeter);
 
400
                clipImage->setDotsPerMeterY(res * GraphicsUtils::InchesPerMeter);
 
401
                QRectF target(0, 0, twidth, theight);
 
402
 
 
403
                QXmlStreamReader reader(clipString);
 
404
                QSvgRenderer renderer(&reader);         
 
405
                QPainter painter;
 
406
                painter.begin(clipImage);
 
407
                renderer.render(&painter, target);
 
408
                painter.end();
 
409
        }
 
410
 
 
411
        svgString = TextUtils::removeXMLEntities(domDocument1.toString());
 
412
 
 
413
        QXmlStreamReader reader(svgString);
 
414
        QSvgRenderer renderer(&reader);
 
415
        bool anyClipped = false;
 
416
        for (int i = 0; i < transformCount1; i++) {
 
417
                QString n = QString::number(i);
 
418
                QRectF bounds = renderer.boundsOnElement(n);
 
419
                QMatrix m = renderer.matrixForElement(n);
 
420
                QDomElement element = leaves1.at(i);
 
421
                QRectF mBounds = m.mapRect(bounds);
 
422
                if (mBounds.left() < sourceRes.left() - 0.1|| mBounds.top() < sourceRes.top() - 0.1 || mBounds.right() > sourceRes.right() + 0.1 || mBounds.bottom() > sourceRes.bottom() + 0.1) {
 
423
                        // element is outside of bounds--squash it so it will be clipped
 
424
                        // we don't care if the board shape is irregular
 
425
                        // since anything printed between the shape and the bounding rectangle 
 
426
                        // will be physically clipped when the board is cut out
 
427
                        element.setTagName("g");
 
428
                        anyClipped = anyConverted = true;
 
429
                }       
 
430
        }
 
431
 
 
432
        if (forWhy == SVG2gerber::ForOutline) {
 
433
                // make one big polygon.  Assume there are no holes in the board
 
434
 
 
435
                if (anyConverted || leaves1.count() > 1) {
 
436
                        anyClipped = true;
 
437
                        foreach (QDomElement l, leaves1) {
 
438
                                l.setTagName("g");
 
439
                        }
 
440
                }
 
441
        }
 
442
 
 
443
        if (clipImage) {
 
444
                QImage another(imgSize, QImage::Format_Mono);
 
445
                another.fill(0xffffffff);
 
446
                another.setDotsPerMeterX(res * GraphicsUtils::InchesPerMeter);
 
447
                another.setDotsPerMeterY(res * GraphicsUtils::InchesPerMeter);
 
448
                QRectF target(0, 0, twidth, theight);
 
449
 
 
450
                svgString = TextUtils::removeXMLEntities(domDocument1.toString());
 
451
                QXmlStreamReader reader(svgString);
 
452
                QSvgRenderer renderer(&reader);
 
453
                QPainter painter;
 
454
                painter.begin(&another);
 
455
                renderer.render(&painter, target);
 
456
                painter.end();
 
457
 
 
458
                for (int i = 0; i < transformCount1; i++) {
 
459
                        QDomElement element = leaves1.at(i);
 
460
                        if (element.tagName().compare("g") == 0) {
 
461
                                // element is already converted to raster space, we'll clip it later
 
462
                                continue;
 
463
                        }
 
464
 
 
465
                        QString n = QString::number(i);
 
466
                        QRectF bounds = renderer.boundsOnElement(n);
 
467
                        QMatrix m = renderer.matrixForElement(n);
 
468
                        QRectF mBounds = m.mapRect(bounds);
 
469
 
 
470
 
 
471
                        int x1 = qFloor(qMax(0.0, mBounds.left() - sourceRes.left()));
 
472
                        int x2 = qCeil(qMin(sourceRes.width(), mBounds.right() - sourceRes.left()));
 
473
                        int y1 = qFloor(qMax(0.0, mBounds.top() - sourceRes.top()));
 
474
                        int y2 = qCeil(qMin(sourceRes.height(), mBounds.bottom() - sourceRes.top()));
 
475
                        
 
476
                        if (pixelsCollide(&another, clipImage, x1, y1, x2, y2)) {
 
477
                                element.setTagName("g");
 
478
                                anyClipped = anyConverted = true;
 
479
                        }
 
480
                }
 
481
        }
 
482
 
 
483
        if (anyClipped) {
 
484
                // svg has been changed by clipping process so get the string again
 
485
                svgString = TextUtils::removeXMLEntities(domDocument1.toString());
 
486
        }
 
487
 
 
488
    if (anyConverted) {
 
489
                for (int i = 0; i < transformCount1; i++) {
 
490
                        QDomElement element1 = leaves1.at(i);
 
491
                        if (element1.tagName().compare("g") != 0) {
 
492
                                // document 1 element svg can be directly converted to gerber
 
493
                                // so remove it from document 2
 
494
                                QDomElement element2 = leaves2.at(i);
 
495
                                element2.setTagName("g");
 
496
                        }
 
497
                }
 
498
                
 
499
 
 
500
                // expand the svg to fill the space of the image
 
501
                QDomElement root = domDocument2.documentElement();
 
502
                root.setAttribute("width", QString("%1px").arg(twidth));
 
503
                root.setAttribute("height", QString("%1px").arg(theight));
 
504
                if (boardRect.x() != 0 || boardRect.y() != 0) {
 
505
                        QString viewBox = root.attribute("viewBox");
 
506
                        QStringList coords = viewBox.split(" ", QString::SkipEmptyParts);
 
507
                        coords[0] = QString::number(sourceRes.left());
 
508
                        coords[1] = QString::number(sourceRes.top());
 
509
                        root.setAttribute("viewBox", coords.join(" "));
 
510
                }
 
511
 
 
512
                QString svg = TextUtils::removeXMLEntities(domDocument2.toString());
 
513
 
 
514
                QStringList exceptions;
 
515
                exceptions << "none" << "";
 
516
                QString toColor("#000000");
 
517
                QByteArray svgByteArray;
 
518
                SvgFileSplitter::changeColors(svg, toColor, exceptions, svgByteArray);
 
519
 
 
520
                QImage image(imgSize, QImage::Format_Mono);
 
521
                image.fill(0xffffffff);
 
522
                image.setDotsPerMeterX(res * GraphicsUtils::InchesPerMeter);
 
523
                image.setDotsPerMeterY(res * GraphicsUtils::InchesPerMeter);
 
524
                QRectF target(0, 0, twidth, theight);
 
525
 
 
526
                QSvgRenderer renderer(svgByteArray);
 
527
                QPainter painter;
 
528
                painter.begin(&image);
 
529
                renderer.render(&painter, target);
 
530
                painter.end();
 
531
                image.invertPixels();                           // need white pixels on a black background for GroundPlaneGenerator
 
532
 
 
533
                if (clipImage != NULL) {
 
534
                        // can this be done with a single blt using composition mode
 
535
                        // if not, grab a scanline instead of testing every pixel
 
536
                        for (int y = 0; y < theight; y++) {
 
537
                                for (int x = 0; x < twidth; x++) {
 
538
                                        if (clipImage->pixel(x, y) != 0xffffffff) {
 
539
                                                image.setPixel(x, y, 0);
 
540
                                        }
 
541
                                }
 
542
                        }
 
543
                }
 
544
 
 
545
#ifndef QT_NO_DEBUG
 
546
                image.save("output.png");
 
547
#endif
 
548
 
 
549
                GroundPlaneGenerator gpg;
 
550
                gpg.setLayerName(layerName);
 
551
                gpg.setMinRunSize(1, 1);
 
552
                if (forWhy == SVG2gerber::ForOutline) {
 
553
                //      int tinyWidth = boardRect.width();
 
554
                //      int tinyHeight = boardRect.height();
 
555
                //      QRectF tinyTarget(0, 0, tinyWidth, tinyHeight);
 
556
                //      QImage tinyImage(tinyWidth, tinyHeight, QImage::Format_Mono);
 
557
                //      QPainter painter;
 
558
                //      painter.begin(&tinyImage);
 
559
                //      renderer.render(&painter, tinyTarget);
 
560
                //      painter.end();
 
561
                //      tinyImage.invertPixels();                               // need white pixels on a black background for GroundPlaneGenerator
 
562
                        gpg.scanOutline(image, image.width(), image.height(), GraphicsUtils::StandardFritzingDPI / res, GraphicsUtils::StandardFritzingDPI, "#000000", false, false, QSizeF(0, 0), 0);
 
563
                }
 
564
                else {
 
565
                        gpg.scanImage(image, image.width(), image.height(), GraphicsUtils::StandardFritzingDPI / res, GraphicsUtils::StandardFritzingDPI, "#000000", false, false, QSizeF(0, 0), 0, sourceRes.topLeft());
 
566
                }
 
567
 
 
568
                if (gpg.newSVGs().count() > 0) {
 
569
                        QDomDocument doc;
 
570
                        TextUtils::mergeSvg(doc, svgString, "");
 
571
                        foreach (QString gsvg, gpg.newSVGs()) {
 
572
                                TextUtils::mergeSvg(doc, gsvg, "");
 
573
                        }
 
574
                        svgString = TextUtils::mergeSvgFinish(doc);
 
575
                }
 
576
        }
 
577
 
 
578
        if (clipImage) delete clipImage;
 
579
 
 
580
        return svgString;
 
581
}
 
582
 
 
583
QString GerberGenerator::cleanOutline(const QString & outlineSvg)
 
584
{
 
585
        QDomDocument doc;
 
586
        doc.setContent(outlineSvg);
 
587
        QList<QDomElement> leaves;
 
588
    QDomElement root = doc.documentElement();
 
589
    TextUtils::collectLeaves(root, leaves);
 
590
 
 
591
        if (leaves.count() == 0) return "";
 
592
        if (leaves.count() == 1) return outlineSvg;
 
593
 
 
594
        if (leaves.count() > 1) {
 
595
                for (int i = 0; i < leaves.count(); i++) {
 
596
                        QDomElement leaf = leaves.at(i);
 
597
                        if (leaf.attribute("id", "").compare(MagicBoardOutlineID) == 0) {
 
598
                                for (int j = 0; j < leaves.count(); j++) {
 
599
                                        if (i != j) {
 
600
                                                leaves.at(j).parentNode().removeChild(leaves.at(j));
 
601
                                        }
 
602
                                }
 
603
 
 
604
                                return doc.toString();
 
605
                        }
 
606
                }
 
607
        }
 
608
 
 
609
        if (leaves.count() == 0) return "";
 
610
 
 
611
        return outlineSvg;
 
612
}