310
317
if (circle.attribute("id").compare("boardoutline", Qt::CaseInsensitive) != 0) continue;
313
qreal centerx = circle.attribute("cx").toDouble();
314
qreal centery = circle.attribute("cy").toDouble();
315
qreal r = circle.attribute("r").toDouble();
322
double centerx = circle.attribute("cx").toDouble();
323
double centery = circle.attribute("cy").toDouble();
324
double r = circle.attribute("r").toDouble();
316
325
if (r == 0) continue;
318
qreal stroke_width = circle.attribute("stroke-width").toDouble();
319
qreal hole = ((2*r) - stroke_width)/1000;
327
double stroke_width = circle.attribute("stroke-width").toDouble();
328
double hole = ((2*r) - stroke_width)/1000;
321
330
if (forWhy == ForDrill) {
322
331
QString drill_cx = QString::number(flipxNoRound(centerx) / 1000, 'f'); // drill file seems to be in inches
345
354
QString fill = circle.attribute("fill");
347
qreal diam = ((2*r) + stroke_width)/1000;
356
double diam = ((2*r) + stroke_width)/1000;
348
357
if (forWhy == ForMask) {
349
358
diam += 2 * MaskClearance;
352
if(fill=="none" && forWhy != ForMask){
361
if(false && fill=="none" && forWhy != ForMask){
353
362
aperture = QString("C,%1X%2").arg(diam, 0, 'f').arg(hole);
399
408
QString aperture;
401
qreal width = rect.attribute("width").toDouble();
402
qreal height = rect.attribute("height").toDouble();
410
double width = rect.attribute("width").toDouble();
411
double height = rect.attribute("height").toDouble();
413
double rx = rect.attribute("rx", "0").toDouble();
414
double ry = rect.attribute("ry", "0").toDouble();
415
if (rx != 0 || ry != 0) {
416
// not sure how to do rounded rects in gerber
404
421
if (width == 0) continue;
405
422
if (height == 0) continue;
407
qreal x = rect.attribute("x").toDouble();
408
qreal y = rect.attribute("y").toDouble();
409
qreal centerx = x + (width/2);
410
qreal centery = y + (height/2);
424
double x = rect.attribute("x").toDouble();
425
double y = rect.attribute("y").toDouble();
426
double centerx = x + (width/2);
427
double centery = y + (height/2);
411
428
QString cx = QString::number(flipx(centerx));
412
429
QString cy = QString::number(flipy(centery));
413
430
QString fill = rect.attribute("fill");
414
qreal stroke_width = rect.attribute("stroke-width").toDouble();
431
double stroke_width = rect.attribute("stroke-width").toDouble();
416
qreal totalx = (width + stroke_width)/1000;
417
qreal totaly = (height + stroke_width)/1000;
418
qreal holex = (width - stroke_width)/1000;
419
qreal holey = (height - stroke_width)/1000;
433
double totalx = (width + stroke_width)/1000;
434
double totaly = (height + stroke_width)/1000;
435
double holex = (width - stroke_width)/1000;
436
double holey = (height - stroke_width)/1000;
421
438
if (forWhy == ForMask) {
422
439
totalx += 2 * MaskClearance;
464
482
// lines - NOTE: this assumes a circular aperture
465
483
for(uint k = 0; k < lineList.length(); k++){
466
484
QDomElement line = lineList.item(k).toElement();
467
if (forWhy == ForOutline && totalCount > 1) {
468
if (line.attribute("id").compare("boardoutline", Qt::CaseInsensitive) != 0) continue;
471
486
// Note: should be no forWhy == ForMask cases
473
qreal x1 = line.attribute("x1").toDouble();
474
qreal y1 = line.attribute("y1").toDouble();
475
qreal x2 = line.attribute("x2").toDouble();
476
qreal y2 = line.attribute("y2").toDouble();
488
double x1 = line.attribute("x1").toDouble();
489
double y1 = line.attribute("y1").toDouble();
490
double x2 = line.attribute("x2").toDouble();
491
double y2 = line.attribute("y2").toDouble();
478
493
standardAperture(line, apertureMap, current_dcode, dcode_index, 0);
497
514
// polys - NOTE: assumes comma- or space- separated formatting
498
for(uint p = 0; p < polyList.length(); p++){
499
QDomElement polygon = polyList.item(p).toElement();
500
if (forWhy == ForOutline && totalCount > 1) {
501
if (polygon.attribute("id").compare("boardoutline", Qt::CaseInsensitive) != 0) continue;
505
QTextStream tempStream(&temp);
506
polygon.save(tempStream, 1);
508
QString points = polygon.attribute("points");
509
QStringList pointList = points.split(QRegExp("\\s+|,"), QString::SkipEmptyParts);
515
qreal startx = pointList.at(0).toDouble();
516
qreal starty = pointList.at(1).toDouble();
517
// move to start - light off
518
pointString += "X" + QString::number(flipx(startx)) + "Y" + QString::number(flipy(starty)) + "D02*\n";
520
// iterate through all other points - light on
521
for(int pt = 2; pt < pointList.length(); pt +=2){
522
qreal ptx = pointList.at(pt).toDouble();
523
qreal pty = pointList.at(pt+1).toDouble();
524
pointString += "X" + QString::number(flipx(ptx)) + "Y" + QString::number(flipy(pty)) + "D01*\n";
527
// move back to start point
528
pointString += "X" + QString::number(flipx(startx)) + "Y" + QString::number(flipy(starty)) + "D01*\n";
530
standardAperture(polygon, apertureMap, current_dcode, dcode_index, 0);
532
bool polyFill = fillNotStroke(polygon, forWhy);
533
// set poly fill if this is actually a filled in shape
536
m_gerber_paths += "G36*\n";
539
m_gerber_paths += pointString;
541
// stop poly fill if this is actually a filled in shape
544
m_gerber_paths += "G37*\n";
547
if (forWhy == ForMask) {
548
// draw the outline, G36 only does the fill
549
standardAperture(polygon, apertureMap, current_dcode, dcode_index, polygon.attribute("stroke-width").toDouble() + (MaskClearance * 2 * 1000));
550
m_gerber_paths += pointString;
554
m_gerber_paths += "D02*\n";
515
for(uint p = 0; p < polyList.length(); p++) {
516
QDomElement polygon = polyList.item(p).toElement();
517
doPoly(polygon, forWhy, totalCount, true, apertureMap, current_dcode, dcode_index, outlineCount);
519
for(uint p = 0; p < polyLineList.length(); p++) {
520
QDomElement polygon = polyList.item(p).toElement();
521
doPoly(polygon, forWhy, totalCount, false, apertureMap, current_dcode, dcode_index, outlineCount);
578
547
pathUserData.string = "";
580
549
SvgFlattener flattener;
581
flattener.parsePath(data, slot, pathUserData, this, true);
550
bool invalid = false;
552
flattener.parsePath(data, slot, pathUserData, this, true);
554
catch (const QString & msg) {
555
DebugDialog::debug("flattener.parsePath failed " + msg);
558
catch (char const *str) {
559
DebugDialog::debug("flattener.parsePath failed " + QString(str));
563
DebugDialog::debug("flattener.parsePath failed");
585
568
// only add paths if they contained gerber-izable path commands (NO CURVES!)
586
569
// TODO: display some informative error for the user
587
if(pathUserData.string.contains("INVALID")) {
570
if (invalid || pathUserData.string.contains("INVALID")) {
588
571
invalidPathsCount++;
622
605
if (forWhy == ForOutline) {
623
606
// add circular aperture with 0 width
624
607
m_gerber_header += "%ADD10C,0.008*%\n";
608
if (outlineCount != 1) {
609
// if we can't find one and only one svg element as the board outline, then go to plan b
627
614
return invalidPathsCount;
630
QString SVG2gerber::standardAperture(QDomElement & element, QHash<QString, QString> & apertureMap, QString & current_dcode, int & dcode_index, qreal stroke_width) {
617
void SVG2gerber::doPoly(QDomElement & polygon, ForWhy forWhy, int totalCount, bool closedCurve,
618
QHash<QString, QString> & apertureMap, QString & current_dcode, int & dcode_index, int & outlineCount)
620
if (forWhy == ForOutline && totalCount > 1) {
621
if (polygon.attribute("id").compare("boardoutline", Qt::CaseInsensitive) != 0) return;
627
//QTextStream tempStream(&temp);
628
//polygon.save(tempStream, 1);
630
QString points = polygon.attribute("points");
631
QStringList pointList = points.split(QRegExp("\\s+|,"), QString::SkipEmptyParts);
637
double startx = pointList.at(0).toDouble();
638
double starty = pointList.at(1).toDouble();
639
// move to start - light off
640
pointString += "X" + QString::number(flipx(startx)) + "Y" + QString::number(flipy(starty)) + "D02*\n";
642
// iterate through all other points - light on
643
for(int pt = 2; pt < pointList.length(); pt +=2){
644
double ptx = pointList.at(pt).toDouble();
645
double pty = pointList.at(pt+1).toDouble();
646
pointString += "X" + QString::number(flipx(ptx)) + "Y" + QString::number(flipy(pty)) + "D01*\n";
650
// move back to start point
651
pointString += "X" + QString::number(flipx(startx)) + "Y" + QString::number(flipy(starty)) + "D01*\n";
654
standardAperture(polygon, apertureMap, current_dcode, dcode_index, 0);
656
bool polyFill = fillNotStroke(polygon, forWhy);
657
// set poly fill if this is actually a filled in shape
660
m_gerber_paths += "G36*\n";
663
m_gerber_paths += pointString;
665
// stop poly fill if this is actually a filled in shape
668
m_gerber_paths += "G37*\n";
671
if (forWhy == ForMask) {
672
// draw the outline, G36 only does the fill
673
standardAperture(polygon, apertureMap, current_dcode, dcode_index, polygon.attribute("stroke-width").toDouble() + (MaskClearance * 2 * 1000));
674
m_gerber_paths += pointString;
678
m_gerber_paths += "D02*\n";
682
QString SVG2gerber::standardAperture(QDomElement & element, QHash<QString, QString> & apertureMap, QString & current_dcode, int & dcode_index, double stroke_width) {
631
683
if (stroke_width == 0) {
632
684
stroke_width = element.attribute("stroke-width").toDouble();
665
717
QDomElement nextLine = nextPath.nextSiblingElement("line");
666
718
if (nextLine.isNull()) return;
668
qreal diameter = parent.attribute("stroke-width").toDouble();
669
qreal cx1 = nextLine.attribute("x1").toDouble();
670
qreal cy1 = nextLine.attribute("y1").toDouble();
671
qreal cx2 = nextLine.attribute("x2").toDouble();
672
qreal cy2 = nextLine.attribute("y2").toDouble();
720
double diameter = parent.attribute("stroke-width").toDouble();
721
double cx1 = nextLine.attribute("x1").toDouble();
722
double cy1 = nextLine.attribute("y1").toDouble();
723
double cx2 = nextLine.attribute("x2").toDouble();
724
double cy2 = nextLine.attribute("y2").toDouble();
674
726
QString drill_aperture = QString("C%1").arg(diameter / 1000, 0, 'f') + "\n";
675
727
if (!m_gerber_header.contains(drill_aperture)) {
782
int SVG2gerber::flipx(qreal x)
838
int SVG2gerber::flipx(double x)
784
840
return qRound(x);
787
int SVG2gerber::flipy(qreal y)
843
int SVG2gerber::flipy(double y)
789
845
return qRound(m_boardSize.height() - y);
792
qreal SVG2gerber::flipxNoRound(qreal x)
848
double SVG2gerber::flipxNoRound(double x)
797
qreal SVG2gerber::flipyNoRound(qreal y)
853
double SVG2gerber::flipyNoRound(double y)
799
855
return m_boardSize.height() - y;