Frontend to the famous GRBL.

eaglebrdparser.cpp 28KB

    /* Part of x2grbl * * Copyright Johann Wilhelm <johann.wilhelm@9mal6.de> 2015 * * see Readme.md for detailed license and usage information! */ #include "eaglebrdparser.h" #include <QDomDocument> #include <QDomNode> #include <QDebug> #include <QGraphicsRectItem> #include <QGraphicsLineItem> #include <QGraphicsEllipseItem> #include <QGraphicsPathItem> #include <QGraphicsPolygonItem> #include <QVector2D> #include "loadeagleboarddialog.h" #include "qpainter2gcode.h" #include <QGraphicsView> const double EagleBrdParser::mm2ps=72.0; EagleBrdParser::EagleBrdParser() { ClearenceWireWire=1; Scene.setBackgroundBrush(QBrush(Qt::yellow)); } bool EagleBrdParser::open(QIODevice &Input) { Polygons.clear(); QMapIterator<int, QGraphicsItemGroup *> i(Layers); while (i.hasNext()) { i.next(); Scene.removeItem(i.value()); delete i.value(); } Layers.clear(); LayerNames.clear(); QDomDocument doc; doc.setContent(&Input); // /eagle/drawing/layers QDomElement drawing=doc.documentElement().firstChildElement(QString("drawing")); QDomElement layers=drawing.firstChildElement(QString("layers")); QDomElement layer=layers.firstChildElement(QString("layer")); while (!layer.isNull()) { int layernumber=layer.attribute(QString("number")).toInt(); QString layername=layer.attribute(QString("name")); int layercolor=layer.attribute(QString("color")).toInt(); int layerfill=layer.attribute(QString("fill")).toInt(); QGraphicsItemGroup *Item=new QGraphicsItemGroup; Layers[layernumber]=Item; Scene.addItem(Item); LayerNames[layernumber]=layername; QColor c=eagleColor2globalColor(layercolor); LayerColors[layernumber]=eagleColor2globalColor(layercolor); LayerPattern[layernumber]=eaglePattern2BrushStyle(layerfill); if (layer.attribute(QString("visible"))==QString("no")) Item->setVisible(false); layer=layer.nextSiblingElement(QString("layer")); } // /eagle/drawing/board/plain QDomElement board=drawing.firstChildElement(QString("board")); QDomElement designrules=board.firstChildElement(QString("designrules")); QDomElement param=designrules.firstChildElement(QString("param")); while (!param.isNull()) { if (param.toElement().attribute("name")==QString("mdWireWire")) { QString Value=param.toElement().attribute("value"); if (Value.contains(QString("mil"))) { Value.replace(QString("mil"), QString("")); ClearenceWireWire=Value.toDouble()*0.0254; } } param=param.nextSiblingElement(QString("param")); } QDomElement plain=board.firstChildElement(QString("plain")); QDomNode node=plain.firstChild(); while (!node.isNull()) { QDomElement element=node.toElement(); double x=element.attribute(QString("x")).toDouble()*mm2ps; double y=element.attribute(QString("y")).toDouble()*mm2ps; QString rot=element.attribute(QString("rot")); bool mirror=rot.contains(QString("M")); //bool spin=rot.contains(QString("S")); //todo: add spin... /* from the eagle-help: S spin flag... text will be roteted M mirror flag... mirrors along the y-axis Rnnn rotates by 0...359.9deg */ while (rot.count() && !rot[0].isDigit()) { rot=rot.remove(0,1); } double rotation=rot.toDouble(); QTransform transform; transform.rotate(rotation); if (mirror) transform.scale(-1,1); parseGraphics(QString(""), element, QPointF(x,y), transform); node=node.nextSibling(); } QDomElement SignalsElement=board.firstChildElement(QString("signals")); QDomElement signal=SignalsElement.firstChildElement(QString("signal")); while (!signal.isNull()) { QString SignalName=signal.attribute(QString("name")); QDomNode node=signal.firstChild(); while (!node.isNull()) { QDomElement element=node.toElement(); double x=element.attribute(QString("x")).toDouble()*mm2ps; double y=element.attribute(QString("y")).toDouble()*mm2ps; QString rot=element.attribute(QString("rot")); bool mirror=rot.contains(QString("M")); //bool spin=rot.contains(QString("S")); //todo: add spin... /* from the eagle-help: S spin flag... text will be roteted M mirror flag... mirrors along the y-axis Rnnn rotates by 0...359.9deg */ while (rot.count() && !rot[0].isDigit()) { rot=rot.remove(0,1); } double rotation=rot.toDouble(); QTransform transform; transform.rotate(rotation); if (mirror) transform.scale(-1,1); parseGraphics(SignalName, element, QPointF(x,y), transform); node=node.nextSibling(); } signal=signal.nextSiblingElement(QString("signal")); } QDomElement libraries=board.firstChildElement(QString("libraries")); QDomElement elements=board.firstChildElement(QString("elements")); QDomElement element=elements.firstChildElement(QString("element")); while (!element.isNull()) { QString LibraryName=element.attribute(QString("library")); QString PackageName=element.attribute(QString("package")); double x=element.attribute(QString("x")).toDouble()*mm2ps; double y=element.attribute(QString("y")).toDouble()*mm2ps; QString rot=element.attribute(QString("rot")); bool mirror=rot.contains(QString("M")); //bool spin=rot.contains(QString("S")); //todo: add spin... /* from the eagle-help: S spin flag... text will be roteted M mirror flag... mirrors along the y-axis Rnnn rotates by 0...359.9deg */ while (rot.count() && !rot[0].isDigit()) { rot=rot.remove(0,1); } double rotation=rot.toDouble(); QTransform transform; transform.rotate(rotation); QPointF pos=QPointF(x,y); if (mirror) transform.scale(-1,1); QDomElement library=libraries.firstChildElement(QString("library")); while (!library.isNull()) { if (library.attribute(("name"))==LibraryName) { QDomElement packages=library.firstChildElement(QString("packages")); QDomElement package=packages.firstChildElement(QString("package")); while (!package.isNull()) { if (package.attribute(QString("name"))==PackageName) { QDomNode graphicelement=package.firstChild(); while (!graphicelement.isNull()) { parseGraphics(QString(""), graphicelement.toElement(), pos, transform); graphicelement=graphicelement.nextSibling(); } break; } package=package.nextSiblingElement(QString("package")); } break; } library=library.nextSiblingElement(QString("library")); } element=element.nextSiblingElement(QString("element")); } QList<QString> SignalNames=this->Signals.keys(); const int signalCount=Signals.count(); for (int i=0;i<signalCount;i++) { QString SignalName=SignalNames[i]; const int polygonCount=Signals[SignalNames[i]]->Polygons.count(); for (int polygon=0;polygon<polygonCount;polygon++) { const int polygonLayer=Signals[SignalNames[i]]->Polygons[polygon]->layer; const double polygonIsolate=Signals[SignalNames[i]]->Polygons[polygon]->isolate; const double polygonWidth=Signals[SignalNames[i]]->Polygons[polygon]->width; QPainterPath Shapes; for (int i=0;i<signalCount;i++) { if (SignalName!=SignalNames[i]) { const int elementCount=this->Signals[SignalNames[i]]->Parts.count(); for (int j=0;j<elementCount;j++) { if (Signals[SignalNames[i]]->Parts[j]->layer==polygonLayer) { eagleSignalPart *part=Signals[SignalNames[i]]->Parts[j]; double PenWidth=part->pathItem->pen().widthF(); QPainterPathStroker stroker; stroker.setWidth(PenWidth); QPainterPath OutlinePath=stroker.createStroke(part->pathItem->path()); QTransform Transform=part->pathItem->transform(); Shapes|=Transform.map(OutlinePath).translated(part->pathItem->pos()); // part->pathItem->setVisible(false); } } } } QPainterPathStroker stroker; stroker.setWidth((std::max(polygonIsolate, ClearenceWireWire)+polygonWidth)*mm2ps); QPainterPath ShapesAndIsolate = stroker.createStroke(Shapes).simplified(); /* QGraphicsPathItem *foo=new QGraphicsPathItem; foo->setPath(ShapesAndIsolate); foo->setPen(QPen(QBrush(Qt::green), 0)); foo->setBrush(QBrush(Qt::green)); Scene.addItem(foo); */ QPainterPath path; path.addPolygon(Signals[SignalNames[i]]->Polygons[polygon]->polygon); Signals[SignalNames[i]]->Polygons[polygon]->pathItem->setPath(path-ShapesAndIsolate); } } return true; } bool EagleBrdParser::SelectLayers() { LoadEagleBoardDialog Dialog(this); return (Dialog.exec()==QDialog::Accepted); } QModelIndex EagleBrdParser::index(int row, int column, const QModelIndex &parent /*= QModelIndex()*/) const { return createIndex(row, column); } QModelIndex EagleBrdParser::parent(const QModelIndex &child) const { return QModelIndex(); } int EagleBrdParser::rowCount(const QModelIndex &parent /*= QModelIndex()*/) const { return Layers.keys().count(); } int EagleBrdParser::columnCount(const QModelIndex &parent /*= QModelIndex()*/) const { if (parent.isValid()) return 0; return 2; } QVariant EagleBrdParser::data(const QModelIndex &index, int role/* = Qt::DisplayRole*/) const { if (role==Qt::DisplayRole) { if (index.column()==0) if (index.row()<Layers.size()) return QVariant(Layers.keys()[index.row()]); else return QVariant(QString("Layer-Mapping Error!")); else if (index.column()==1) { if (index.row()<LayerNames.size()) return QVariant(LayerNames.values()[index.row()]); else return QVariant(QString("Layer-Mapping Error!")); } else { return QVariant(QString("Internal Error!")); } } if (role==Qt::CheckStateRole) { if (index.column()==0) if (index.row()<Layers.size()) return (Layers.values()[index.row()]->isVisible())?Qt::Checked : Qt::Unchecked; } return QVariant(); } Qt::ItemFlags EagleBrdParser::flags(const QModelIndex &index) const { if (index.column()==0) return QAbstractItemModel::flags(index) | Qt::ItemIsUserCheckable; return QAbstractItemModel::flags(index); } bool EagleBrdParser::setData(const QModelIndex & index, const QVariant & value, int role /*= Qt::EditRole*/) { if (role==Qt::CheckStateRole) { if (index.row()<Layers.size()) { Layers.values()[index.row()]->setVisible(!Layers.values()[index.row()]->isVisible()); emit dataChanged(index,index); return true; } } return false; } QColor EagleBrdParser::eagleColor2globalColor(int color) { switch(color) { case 0: return QColor(Qt::black); case 1: return QColor(Qt::darkBlue); case 2: return QColor(Qt::darkGray); case 3: return QColor(Qt::darkCyan); case 4: return QColor(Qt::darkRed); case 5: return QColor(Qt::darkMagenta); case 6: return QColor(Qt::darkYellow); case 7: return QColor(Qt::lightGray); case 8: return QColor(Qt::darkGray); case 9: return QColor(Qt::blue); case 10: return QColor(Qt::green); case 11: return QColor(Qt::cyan); case 12: return QColor(Qt::red); case 13: return QColor(Qt::magenta); case 14: return QColor(Qt::yellow); case 15: return QColor(Qt::white); default: return Qt::black; } } Qt::BrushStyle EagleBrdParser::eaglePattern2BrushStyle(int pattern) { return Qt::SolidPattern; switch(pattern) { case 0: return Qt::NoBrush; case 1: return Qt::SolidPattern; case 2: return Qt::HorPattern; case 3: return Qt::BDiagPattern; case 4: return Qt::FDiagPattern; case 5: return Qt::VerPattern; case 6: return Qt::DiagCrossPattern; case 7: return Qt::CrossPattern; case 8: return Qt::Dense1Pattern; case 9: return Qt::Dense2Pattern; case 10: return Qt::Dense3Pattern; case 11: return Qt::Dense4Pattern; case 12: return Qt::Dense5Pattern; case 13: return Qt::Dense6Pattern; case 14: return Qt::Dense7Pattern; case 15: return Qt::RadialGradientPattern; default: return Qt::SolidPattern; } } void EagleBrdParser::parseGraphics(QString SignalName, QDomElement element, QPointF pos, QTransform transform) { if (!Signals.contains(SignalName)) { Signals[SignalName]=new eagleSignal; } if (element.hasAttribute(QString("layer"))) { int layer=element.attribute(QString("layer")).toInt(); if (Layers.contains(layer)) { if (element.tagName() == "rectangle") { double x1=element.attribute(QString("x1")).toDouble()*mm2ps; double y1=element.attribute(QString("y1")).toDouble()*mm2ps; double x2=element.attribute(QString("x2")).toDouble()*mm2ps; double y2=element.attribute(QString("y2")).toDouble()*mm2ps; QGraphicsPathItem *item=new QGraphicsPathItem; QPainterPath path; path.moveTo(x1,y1); path.lineTo(x2,y1); path.lineTo(x2,y2); path.lineTo(x1,y2); path.lineTo(x1,y1); item->setPath(path); item->setPen(QPen(QBrush(LayerColors[layer], LayerPattern[layer]), 0)); item->setBrush(QBrush(LayerColors[layer], LayerPattern[layer])); item->setPos(pos); item->setTransform(transform); Layers[layer]->addToGroup(item); eagleSignalPart *signalPart=new eagleSignalPart; signalPart->layer=layer; signalPart->pathItem=item; Signals[SignalName]->Parts.append(signalPart); } else if (element.tagName() == "smd") { double x=element.attribute(QString("x")).toDouble()*mm2ps; double y=element.attribute(QString("y")).toDouble()*mm2ps; double dx=element.attribute(QString("dx")).toDouble()*mm2ps; double dy=element.attribute(QString("dy")).toDouble()*mm2ps; QGraphicsPathItem *item=new QGraphicsPathItem; QPainterPath path; path.addRect(x-dx/2, y-dy/2, dx, dy); path.setFillRule(Qt::WindingFill); item->setPath(path); item->setPen(QPen(QBrush(LayerColors[layer], LayerPattern[layer]), 0)); item->setBrush(QBrush(LayerColors[layer], LayerPattern[layer])); item->setPos(pos); item->setTransform(transform); Layers[layer]->addToGroup(item); eagleSignalPart *signalPart=new eagleSignalPart; signalPart->layer=layer; signalPart->pathItem=item; Signals[SignalName]->Parts.append(signalPart); } else if (element.tagName() == "polygon") { double width=element.toElement().attribute("width").toDouble()*mm2ps; QPolygonF polygon; QDomElement vertex=element.firstChildElement(QString("vertex")); while(!vertex.isNull()) { double x=vertex.attribute(QString("x")).toDouble()*mm2ps; double y=vertex.attribute(QString("y")).toDouble()*mm2ps; polygon.append(QPointF(x,y)); vertex=vertex.nextSiblingElement(QString("vertex")); } QGraphicsPathItem *item=new QGraphicsPathItem; QPainterPath path; path.addPolygon(polygon); item->setPath(path); QColor c=LayerColors[layer]; c.setAlphaF(1); item->setPen(QPen(QBrush(c, LayerPattern[layer]), width)); item->setBrush(QBrush(c, LayerPattern[layer])); item->setPos(pos); item->setTransform(transform); Layers[layer]->addToGroup(item); eagleSignalPolygons *signalPolygon=new eagleSignalPolygons; signalPolygon->layer=layer; signalPolygon->pathItem=item; signalPolygon->isolate=ClearenceWireWire; signalPolygon->width=width/mm2ps; signalPolygon->polygon=polygon; Signals[SignalName]->Polygons.append(signalPolygon); } else if (element.tagName() == "wire") { double x1=element.attribute(QString("x1")).toDouble()*mm2ps; double y1=element.attribute(QString("y1")).toDouble()*mm2ps; double x2=element.attribute(QString("x2")).toDouble()*mm2ps; double y2=element.attribute(QString("y2")).toDouble()*mm2ps; double width=element.attribute(QString("width")).toDouble()*mm2ps; if (element.hasAttribute(QString("curve"))) { double curve=element.attribute(QString("curve")).toDouble(); curve*=2*M_PI; curve/=360; QVector2D A=QVector2D(x1, y1); QVector2D B=QVector2D(x2, y2); QVector2D C; //Center QVector2D D; //point at AB/2 QVector2D AB=B-A; QVector2D n=QVector2D(AB.y(), -AB.x()).normalized(); D=A+AB.normalized()*AB.length()/2.0; double ab_2=AB.length()/2; double r=ab_2 / sin(curve/2); double h=sqrt(r*r-ab_2*ab_2); C=D+n*h; QVector2D AC=A-C; QVector2D BC=B-C; if (QVector2D::dotProduct(AB, BC)*curve>0) { C=D-n*h; } A-=C; double alpha1=acos(A.x()/A.length()); double alpha2=asin(A.y()/A.length()); double alpha=alpha1; if (alpha2>0) alpha*=-1; r=fabs(r); QGraphicsPathItem *item=new QGraphicsPathItem; QPainterPath path; path.moveTo((A+C).x(), (A+C).y()); path.arcTo(C.x()-r, C.y()-r, 2*r, 2*r, alpha*180/M_PI, -curve*180/M_PI); item->setPen(QPen(QBrush(LayerColors[layer], LayerPattern[layer]), width, Qt::SolidLine, Qt::RoundCap)); item->setPath(path); item->setPos(pos); item->setTransform(transform); Layers[layer]->addToGroup(item); eagleSignalPart *signalPart=new eagleSignalPart; signalPart->layer=layer; signalPart->pathItem=item; Signals[SignalName]->Parts.append(signalPart); } else { QGraphicsPathItem *item=new QGraphicsPathItem; item->setPen(QPen(QBrush(LayerColors[layer], LayerPattern[layer]), width, Qt::SolidLine, Qt::RoundCap)); item->setBrush(Qt::NoBrush); QPainterPath path; path.moveTo(x1,y1); path.lineTo(x2,y2); item->setPath(path); item->setPos(pos); item->setTransform(transform); Layers[layer]->addToGroup(item); eagleSignalPart *signalPart=new eagleSignalPart; signalPart->layer=layer; signalPart->pathItem=item; Signals[SignalName]->Parts.append(signalPart); } } else if (element.tagName() == "text") { QString Text; QDomNode node=element.firstChild(); while (!node.isNull()) { if (node.isText()) { Text+=node.toText().data(); } node=node.nextSibling(); } double Size=element.attribute(QString("size")).toDouble()*mm2ps; QGraphicsPathItem *item=new QGraphicsPathItem; item->setPen(QPen(QBrush(LayerColors[layer], LayerPattern[layer]), 0)); item->setBrush(QBrush(LayerColors[layer], LayerPattern[layer])); QPainterPath path; QFont font; font.setFamily(font.defaultFamily()); font.setPointSizeF(Size); path.addText(0,0,font, Text); item->setPath(path); item->setPos(pos); item->setTransform(transform); Layers[layer]->addToGroup(item); eagleSignalPart *signalPart=new eagleSignalPart; signalPart->layer=layer; signalPart->pathItem=item; Signals[SignalName]->Parts.append(signalPart); } else if (element.tagName() == "circle") { double x=element.attribute(QString("x")).toDouble()*mm2ps; double y=element.attribute(QString("y")).toDouble()*mm2ps; double width=element.attribute(QString("width")).toDouble()*mm2ps; double radius=element.attribute(QString("radius")).toDouble()*mm2ps; QGraphicsPathItem *item=new QGraphicsPathItem; QPainterPath path; path.addEllipse(x-radius,y-radius,2*radius, 2*radius); item->setPath(path); item->setPen(QPen(QBrush(LayerColors[layer], LayerPattern[layer]), width)); item->setBrush(QBrush(LayerColors[layer], Qt::NoBrush)); item->setTransform(transform); Layers[layer]->addToGroup(item); eagleSignalPart *signalPart=new eagleSignalPart; signalPart->layer=layer; signalPart->pathItem=item; Signals[SignalName]->Parts.append(signalPart); } else { qDebug()<<"unknown element "<< element.tagName()<<"\n"; } } else qDebug()<<"unknown layer "<< layer <<"\n"; } else { if (element.tagName() == "hole") { double x=element.attribute(QString("x")).toDouble()*mm2ps; double y=element.attribute(QString("y")).toDouble()*mm2ps; double drill=element.attribute(QString("drill")).toDouble()*mm2ps; QGraphicsEllipseItem *item=new QGraphicsEllipseItem(x-drill/2.0,y-drill/2.0,drill, drill); item->setPen(QPen(Scene.backgroundBrush(), 0)); item->setBrush(Scene.backgroundBrush()); item->setPen(QPen(QBrush(LayerColors[45], LayerPattern[45]), 0)); item->setBrush(QBrush(LayerColors[45], Qt::SolidPattern)); item->setPos(pos); item->setTransform(transform); Layers[45]->addToGroup(item); } else if (element.tagName() == "pad" || element.tagName() == "via") { double x=element.attribute(QString("x")).toDouble()*mm2ps; double y=element.attribute(QString("y")).toDouble()*mm2ps; QString shape=element.attribute(QString("shape")); int layer=17; if (element.tagName() == "via") layer=18; double drill=element.attribute(QString("drill")).toDouble()*mm2ps; QGraphicsEllipseItem *item=new QGraphicsEllipseItem(x-drill/2.0,y-drill/2.0,drill, drill); item->setPen(QPen(QBrush(LayerColors[45], LayerPattern[45]), 0)); item->setBrush(QBrush(LayerColors[45], Qt::SolidPattern)); item->setPos(pos); item->setTransform(transform); Layers[45]->addToGroup(item); if (shape==QString("long")) { double dx=1*(drill+.4); double dy=2*(drill+.4); QGraphicsEllipseItem *pad=new QGraphicsEllipseItem(x-dx/2, y-dy/2,dx, dy); pad->setPen(QPen(QBrush(LayerColors[layer], LayerPattern[layer]), 0)); pad->setBrush(QBrush(LayerColors[layer], LayerPattern[layer])); pad->setPos(pos); pad->setTransform(transform); Layers[layer]->addToGroup(pad); } if (shape==QString("")) { double dx=1*(drill+.4); double dy=1*(drill+.4); QGraphicsEllipseItem *pad=new QGraphicsEllipseItem(x-dx/2, y-dy/2,dx, dy); pad->setPen(QPen(QBrush(LayerColors[layer], LayerPattern[layer]), 0)); pad->setBrush(QBrush(LayerColors[layer], LayerPattern[layer])); pad->setPos(pos); pad->setTransform(transform); Layers[layer]->addToGroup(pad); } if (shape==QString("octagon")) { double dx=1*(drill+.4); double dy=1*(drill+.4); QGraphicsEllipseItem *pad=new QGraphicsEllipseItem(x-dx/2, y-dy/2,dx, dy); pad->setPen(QPen(QBrush(LayerColors[layer], LayerPattern[layer]), 0)); pad->setBrush(QBrush(LayerColors[layer], LayerPattern[layer])); pad->setPos(pos); pad->setTransform(transform); Layers[layer]->addToGroup(pad); } if (shape==QString("square")) { //todo: good approx... double dx=1*(drill+.4); double dy=1*(drill+.4); QGraphicsRectItem *pad=new QGraphicsRectItem(x-dx/2, y-dy/2,dx, dy); pad->setPen(QPen(QBrush(LayerColors[layer], LayerPattern[layer]), 0)); pad->setBrush(QBrush(LayerColors[layer], LayerPattern[layer])); pad->setPos(pos); pad->setTransform(transform); Layers[layer]->addToGroup(pad); } } } } void EagleBrdParser::InitParser(GCodeParser &Parser) { QPainter2GCode GcodeGenerator; QPainter painter(&GcodeGenerator); Scene.setBackgroundBrush(QBrush(Qt::NoBrush)); Scene.render(&painter,Scene.itemsBoundingRect(), Scene.itemsBoundingRect(), Qt::KeepAspectRatio); painter.end(); GcodeGenerator.InitParser(Parser); }