1
/*******************************************************************
3
Part of the Fritzing project - http://fritzing.org
4
Copyright (c) 2007-2009 Fachhochschule Potsdam - http://fh-potsdam.de
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.
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.
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/>.
19
********************************************************************
22
$Author: cohen@irascible.com $:
23
$Date: 2012-09-14 23:34:09 +0200 (Fri, 14 Sep 2012) $
25
********************************************************************/
30
#include <QTextStream>
32
#include "../debugdialog.h"
34
// this module converts fritzing footprint xml files to svg
36
// TODO: mask and keepout layers
38
// TODO: square pins and round pads?
40
PcbXML::PcbXML( const QDomElement & pcbDocument )
42
// TODO: need some execption handling for bad elements missing attrs, etc.
43
m_svg = new SVGDomDocument();
44
m_svgroot = m_svg->documentElement();
46
// FIXME: what happens when there is no mark - should be 0
47
m_markx = pcbDocument.attribute("MX").toInt();
48
m_marky = pcbDocument.attribute("MY").toInt();
49
m_units = pcbDocument.attribute("units");
58
m_silkscreen = m_svg->createGroup("silkscreen");
59
m_copper = m_svg->createGroup("copper0");
60
m_keepout = m_svg->createGroup("keepout");
61
m_mask = m_svg->createGroup("soldermask");
62
m_outline = m_svg->createGroup("outline");
64
QDomNodeList tagList = pcbDocument.childNodes();
66
//TODO: eventually need to support recursing into the tree here
67
//TODO: support footprints with multiple root elements (module style)
68
for(uint i = 0; i < tagList.length(); i++){
69
drawNode(tagList.item(i));
72
m_svg->setHeight(m_maxy-m_miny, m_units);
73
m_svg->setWidth(m_maxx-m_minx, m_units);
74
m_svg->setViewBox(0,0,m_maxx-m_minx,m_maxy-m_miny);
78
m_svgFile = QDir::tempPath () + "/footprint.svg";
79
DebugDialog::debug(QString("temp path %1").arg(QDir::tempPath () + "/test.svg" ) );
80
m_svg->save(m_svgFile);
83
QString PcbXML::getSvgFile(){
87
void PcbXML::drawNode(QDomNode node){
88
DebugDialog::debug("drawing node:");
90
QString tag = node.nodeName().toLower();
93
DebugDialog::debug("\tPin");
97
DebugDialog::debug("\tPad");
100
else if(tag=="elementline"){
101
DebugDialog::debug("\tElementLine");
102
drawElementLine(node);
104
else if(tag=="elementarc"){
105
DebugDialog::debug("\tElementArc");
106
drawElementArc(node);
108
else if(tag=="mark"){
109
DebugDialog::debug("\tMark");
113
DebugDialog::debug("cannot draw - unrecognized tag");
117
void PcbXML::drawPin(QDomNode node){
118
QDomElement element = node.toElement();
119
QDomElement pin = m_svg->createElement("circle");
123
if( element.hasAttribute("aX") ){
124
x = element.attribute("aX").toInt();
125
y = element.attribute("aY").toInt();
128
x = element.attribute("rX").toInt() + m_markx;
129
y = element.attribute("rY").toInt() + m_marky;
132
int drill = element.attribute("Drill").toInt()/2;
133
int thickness = element.attribute("Thickness").toInt()/2 - drill;
134
int radius = drill + thickness/2;
135
QString id = QString("connector%1pin").arg(m_pinCount);
137
// BUG: what's up with str -> hex conversion???
140
if(element.hasAttribute("NFlags")) {
141
square = element.attribute("NFlags").toInt(&verify,16) & 0x0100;
143
else if(element.hasAttribute("SFlags")) {
144
square = element.attribute("SFlags").toInt(&verify,16) & 0x0100;
146
//DebugDialog::debug(QString("NFlags: %1 Value:%2 Square:%3").arg(element.attribute("NFlags")).arg(element.attribute("NFlags").toInt(&verify,16)).arg(square));
151
QDomElement sq = m_svg->createElement("rect");
152
sq.setAttribute("x",x-radius);
153
sq.setAttribute("y",y-radius);
154
sq.setAttribute("fill", "none");
155
sq.setAttribute("width",radius*2);
156
sq.setAttribute("height",radius*2);
157
sq.setAttribute("stroke", "rgb(255, 191, 0)");
158
sq.setAttribute("stroke-width", thickness);
159
QDomNode tempsq = m_copper.appendChild(sq);
162
pin.setAttribute("cx", x);
163
pin.setAttribute("cy", y);
164
pin.setAttribute("r", radius);
165
pin.setAttribute("stroke", "rgb(255, 191, 0)");
166
pin.setAttribute("stroke-width", thickness);
167
pin.setAttribute("id", id);
168
pin.setAttribute("fill", "none");
170
QDomNode temp = m_copper.appendChild(pin);
171
minMax(x,y,radius+(thickness/2));
174
void PcbXML::drawPad(QDomNode node){
175
QDomElement element = node.toElement();
176
QDomElement pad = m_svg->createElement("rect");
178
// TODO: mask and keepout layers
179
int x1 = qMin(element.attribute("rX1").toInt(),element.attribute("rX2").toInt()) + m_markx;
180
int x2 = qMax(element.attribute("rX1").toInt(),element.attribute("rX2").toInt()) + m_markx;
181
int y1 = qMin(element.attribute("rY1").toInt(),element.attribute("rY2").toInt()) + m_marky;
182
int y2 = qMax(element.attribute("rY1").toInt(),element.attribute("rY2").toInt()) + m_marky;
183
int thickness = element.attribute("Thickness").toInt();
184
QString id = "connector" + QString::number(m_padCount) + "pad";
188
int x = x1 - (thickness/2);
189
int y = y1 - (thickness/2);
190
int width = x2 - x1 + thickness;
191
int height = y2 -y1 + thickness;
193
pad.setAttribute("x", x);
194
pad.setAttribute("y", y);
195
pad.setAttribute("width", width);
196
pad.setAttribute("height", height);
197
pad.setAttribute("fill", "rgb(255, 191, 0)");
198
pad.setAttribute("id", id);
200
QDomNode temp = m_copper.appendChild(pad);
202
minMax(x+width,y+height,0);
205
void PcbXML::drawElementLine(QDomNode node){
206
QDomElement element = node.toElement();
207
QDomElement line = m_svg->createElement("line");
209
int x1 = element.attribute("X1").toInt() + m_markx;
210
int y1 = element.attribute("Y1").toInt() + m_marky;
211
int x2 = element.attribute("X2").toInt() + m_markx;
212
int y2 = element.attribute("Y2").toInt() + m_marky;
213
int thickness = element.attribute("Thickness").toInt();
215
line.setAttribute("x1", x1);
216
line.setAttribute("y1", y1);
217
line.setAttribute("x2", x2);
218
line.setAttribute("y2", y2);
219
line.setAttribute("stroke", "white");
220
line.setAttribute("stroke-width", thickness);
221
QDomNode temp = m_silkscreen.appendChild(line);
222
minMax(x1,y1,thickness);
223
minMax(x2,y2,thickness);
226
void PcbXML::drawElementArc(QDomNode node){
227
QDomElement element = node.toElement();
229
// TODO: implement this with cubic bezier in svg
231
int x = element.attribute("X").toInt() + m_markx;
232
int y = element.attribute("Y").toInt() + m_marky;
233
//int width = element.attribute("width").toInt()/2;
234
//int height = element.attribute("height").toInt()/2;
235
//int startangle = element.attribute("StartAngle").toInt();
236
//int endangle = element.attribute("Delta").toInt() + startangle;
237
//int thickness = element.attribute("Thickness").toInt();
239
QString path = "M" + QString::number(x) + "," + QString::number(y) + " ";
244
void PcbXML::drawMark(QDomNode /*node*/){
245
//QDomElement element = node.toElement();QDomElement element = node.toElement();
247
//int ax = element.attribute("aX").toInt(); int ax = element.attribute("aX").toInt();
248
//int ay = element.attribute("aY").toInt(); int ay = element.attribute("aY").toInt();
249
//int radius = element.attribute("Drill").toInt()/2; int radius = element.attribute("Drill").toInt()/2;
250
//int thickness = element.attribute("Thickness").toInt(); int thickness = element.attribute("Thickness").toInt();
254
// checks to see if input is greater or less than current min max
255
// adjust viewbox accordingly
256
void PcbXML::minMax(int x, int y, int width){
257
m_minx = qMin(x-width, m_minx);
258
m_miny = qMin(y-width, m_miny);
259
m_maxx = qMax(x+width, m_maxx);
260
m_maxy = qMax(y+width, m_maxy);
263
// given minimum x and y coordinates shift all elements to upper left corner
264
void PcbXML::shiftCoordinates(){
266
QDomNodeList lineList = m_svgroot.elementsByTagName("line");
267
for(uint i = 0; i < lineList.length(); i++){
268
QDomElement line = lineList.item(i).toElement();
269
float x1 = line.attribute("x1").toFloat() - m_minx;
270
line.setAttribute("x1", x1);
271
float x2 = line.attribute("x2").toFloat() - m_minx;
272
line.setAttribute("x2", x2);
273
float y1 = line.attribute("y1").toFloat() - m_miny;
274
line.setAttribute("y1", y1);
275
float y2 = line.attribute("y2").toFloat() - m_miny;
276
line.setAttribute("y2", y2);
280
QDomNodeList circleList = m_svgroot.elementsByTagName("circle");
281
for(uint i = 0; i < circleList.length(); i++){
282
QDomElement circle = circleList.item(i).toElement();
283
float cx = circle.attribute("cx").toFloat() - m_minx;
284
circle.setAttribute("cx",cx);
285
float cy = circle.attribute("cy").toFloat() - m_miny;
286
circle.setAttribute("cy",cy);
290
QDomNodeList rectList = m_svgroot.elementsByTagName("rect");
291
for(uint i = 0; i < rectList.length(); i++){
292
QDomElement rect = rectList.item(i).toElement();
293
float x = rect.attribute("x").toFloat() - m_minx;
294
rect.setAttribute("x", x);
295
float y = rect.attribute("y").toFloat() - m_miny;
296
rect.setAttribute("y", y);