#include "symbol.h" #include <QDebug> #include <QtMath> #include <QTransform> class PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbol) public: PcbCamSymbolPrivate() { } virtual ~PcbCamSymbolPrivate() { } QString name; PcbCam::SymbolType type {PcbCam::Sym_User}; mutable QPainterPath shape; mutable QRectF boundingRect; public: PcbCamSymbol *q_ptr {nullptr}; }; PcbCamSymbol::PcbCamSymbol() : d_ptr(new PcbCamSymbolPrivate) { d_ptr->q_ptr = this; } PcbCamSymbol::~PcbCamSymbol() { } QString PcbCamSymbol::name() const { Q_D(const PcbCamSymbol); return d->name; } QRectF PcbCamSymbol::boundingRect() const { Q_D(const PcbCamSymbol); if (d->boundingRect.isEmpty()) { d->boundingRect = shape().controlPointRect(); } return d->boundingRect; } PcbCam::SymbolType PcbCamSymbol::type() const { Q_D(const PcbCamSymbol); return d->type; } PcbCamSymbol::PcbCamSymbol(PcbCamSymbolPrivate &dd) : d_ptr(&dd) { d_ptr->q_ptr = this; } /********************* r10 *****************/ class PcbCamSymbolRPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolR) public: PcbCamSymbolRPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolRPrivate() { } qreal size {0.0}; }; PcbCamSymbolR::PcbCamSymbolR(const QString iName) : PcbCamSymbol(*new PcbCamSymbolRPrivate) { Q_D(PcbCamSymbolR); d->type = PcbCam::Sym_R; d->name = iName; QRegularExpression re("^r([0-9.]+)$"); d->size = re.match(d->name).captured(1).toDouble()/1000.0; } PcbCamSymbolR::~PcbCamSymbolR() { } QPainterPath PcbCamSymbolR::shape() const { Q_D(const PcbCamSymbolR); if (d->shape.isEmpty()) { d->shape.addEllipse(QRectF(-d->size/2.0, -d->size/2.0, d->size, d->size)); } return d->shape; } qreal PcbCamSymbolR::size() const { Q_D(const PcbCamSymbolR); return d->size; } /********************* s10 *****************/ class PcbCamSymbolSPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolS) public: PcbCamSymbolSPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolSPrivate() { } qreal size {0.0}; }; PcbCamSymbolS::PcbCamSymbolS(const QString iName) : PcbCamSymbol(*new PcbCamSymbolSPrivate) { Q_D(PcbCamSymbolS); d->type = PcbCam::Sym_S; d->name = iName; QRegularExpression re("^s([0-9.]+)$"); d->size = re.match(d->name).captured(1).toDouble()/1000.0; } PcbCamSymbolS::~PcbCamSymbolS() { } QPainterPath PcbCamSymbolS::shape() const { Q_D(const PcbCamSymbolS); if (d->shape.isEmpty()) { d->shape.addRect(QRectF(-d->size/2.0, -d->size/2.0, d->size, d->size)); } return d->shape; } qreal PcbCamSymbolS::size() const { Q_D(const PcbCamSymbolS); return d->size; } /********************* rect10x20 *****************/ class PcbCamSymbolRectPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolRect) public: PcbCamSymbolRectPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolRectPrivate() { } QSizeF size ; }; PcbCamSymbolRect::PcbCamSymbolRect(const QString iName) : PcbCamSymbol(*new PcbCamSymbolRectPrivate) { Q_D(PcbCamSymbolRect); d->type = PcbCam::Sym_Rect; d->name = iName; QRegularExpression re("^rect([0-9.]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->size = QSizeF(match.captured(1).toDouble()/1000.0, match.captured(2).toDouble()/1000.0); } PcbCamSymbolRect::~PcbCamSymbolRect() { } QPainterPath PcbCamSymbolRect::shape() const { Q_D(const PcbCamSymbolRect); if (d->shape.isEmpty()) { d->shape.addRect(QRectF(-d->size.width()/2.0, -d->size.height()/2.0, d->size.width(), d->size.height())); } return d->shape; } QSizeF PcbCamSymbolRect::size() const { Q_D(const PcbCamSymbolRect); return d->size; } /********************* rect60x30xr5x13 *****************/ class PcbCamSymbolRectRPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolRectR) public: PcbCamSymbolRectRPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolRectRPrivate() { } qreal width {0.0} ; qreal height {0.0} ; qreal radius {0.0}; QString corners {""}; }; PcbCamSymbolRectR::PcbCamSymbolRectR(const QString iName) : PcbCamSymbol(*new PcbCamSymbolRectRPrivate) { Q_D(PcbCamSymbolRectR); d->type = PcbCam::Sym_RectR; d->name = iName; QRegularExpression re("^rect([0-9.]+)x([0-9.]+)xr([0-9.]+)(?:x([1-4]+))?$"); QRegularExpressionMatch match = re.match(d->name); d->width = match.captured(1).toDouble()/1000.0; d->height = match.captured(2).toDouble()/1000.0; d->radius = match.captured(3).toDouble()/1000.0; d->corners = match.captured(4); } PcbCamSymbolRectR::~PcbCamSymbolRectR() { } QPainterPath PcbCamSymbolRectR::shape() const { Q_D(const PcbCamSymbolRectR); if (d->shape.isEmpty()) { QRectF rect(-d->width/2.0, -d->height/2.0, d->width, d->height); QRectF r = rect.normalized(); qreal x = r.x(); qreal y = r.y(); qreal w = r.width(); qreal h = r.height(); QString cor = d->corners; if (cor.isEmpty()) cor = "1234"; if (cor.contains('3')) { d->shape.arcMoveTo(x, y, d->radius*2.0, d->radius*2.0, 180); d->shape.arcTo(x, y, d->radius*2.0, d->radius*2.0, 180, -90); } else { d->shape.moveTo(x, y); d->shape.lineTo(x + w - d->radius, y); } if (cor.contains('4')) { d->shape.arcTo(x + w - d->radius*2.0, y, d->radius*2.0 , d->radius*2.0, 90, -90); } else { d->shape.lineTo(x + w, y); d->shape.lineTo(x + w, y + h - d->radius); } if (cor.contains('1')) { d->shape.arcTo(x + w - d->radius*2.0, y + h - d->radius*2.0, d->radius*2.0, d->radius*2.0, 0, -90); } else { d->shape.lineTo(x + w, y + h); d->shape.lineTo(x + d->radius, y + h); } if (cor.contains('2')) { d->shape.arcTo(x, y + h - d->radius*2.0, d->radius*2.0, d->radius*2.0, 270, -90); } else { d->shape.lineTo(x, y + h); } d->shape.closeSubpath(); } return d->shape; } qreal PcbCamSymbolRectR::width() const { Q_D(const PcbCamSymbolRectR); return d->width; } qreal PcbCamSymbolRectR::height() const { Q_D(const PcbCamSymbolRectR); return d->height; } qreal PcbCamSymbolRectR::radius() const { Q_D(const PcbCamSymbolRectR); return d->radius; } QString PcbCamSymbolRectR::corners() const { Q_D(const PcbCamSymbolRectR); return d->corners; } /********************* rect60x30xc5x13 *****************/ class PcbCamSymbolRectCPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolRectC) public: PcbCamSymbolRectCPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolRectCPrivate() { } qreal width {0.0} ; qreal height {0.0} ; qreal radius {0.0}; QString corners {""}; }; PcbCamSymbolRectC::PcbCamSymbolRectC(const QString iName) : PcbCamSymbol(*new PcbCamSymbolRectCPrivate) { Q_D(PcbCamSymbolRectC); d->type = PcbCam::Sym_RectC; d->name = iName; QRegularExpression re("^rect([0-9.]+)x([0-9.]+)xc([0-9.]+)(?:x([1-4]+))?$"); QRegularExpressionMatch match = re.match(d->name); d->width = match.captured(1).toDouble()/1000.0; d->height = match.captured(2).toDouble()/1000.0; d->radius = match.captured(3).toDouble()/1000.0; d->corners = match.captured(4); } PcbCamSymbolRectC::~PcbCamSymbolRectC() { } QPainterPath PcbCamSymbolRectC::shape() const { Q_D(const PcbCamSymbolRectC); if (d->shape.isEmpty()) { QRectF rect(-d->width/2.0, -d->height/2.0, d->width, d->height); QRectF r = rect.normalized(); qreal x = r.x(); qreal y = r.y(); qreal w = r.width(); qreal h = r.height(); QString cor = d->corners; if (cor.isEmpty()) cor = "1234"; if (cor.contains('3')) { d->shape.moveTo(x, y + d->radius); d->shape.lineTo(x + d->radius, y); d->shape.lineTo(x + w - d->radius, y); } else { d->shape.moveTo(x, y); d->shape.lineTo(x + w - d->radius, y); } if (cor.contains('4')) { d->shape.lineTo(x + w, y + d->radius); d->shape.lineTo(x + w, y + h - d->radius); } else { d->shape.lineTo(x + w, y); d->shape.lineTo(x + w, y + h - d->radius); } if (cor.contains('1')) { d->shape.lineTo(x + w - d->radius, y + h); d->shape.lineTo(x + d->radius, y + h); } else { d->shape.lineTo(x + w, y + h); d->shape.lineTo(x + d->radius, y + h); } if (cor.contains('2')) { d->shape.lineTo(x, y + h - d->radius); } else { d->shape.lineTo(x, y + h); } d->shape.closeSubpath(); } return d->shape; } qreal PcbCamSymbolRectC::width() const { Q_D(const PcbCamSymbolRectC); return d->width; } qreal PcbCamSymbolRectC::height() const { Q_D(const PcbCamSymbolRectC); return d->height; } qreal PcbCamSymbolRectC::radius() const { Q_D(const PcbCamSymbolRectC); return d->radius; } QString PcbCamSymbolRectC::corners() const { Q_D(const PcbCamSymbolRectC); return d->corners; } /********************* oval100x50 *****************/ class PcbCamSymbolOvalPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolOval) public: PcbCamSymbolOvalPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolOvalPrivate() { } QSizeF size ; }; PcbCamSymbolOval::PcbCamSymbolOval(const QString iName) : PcbCamSymbol(*new PcbCamSymbolOvalPrivate) { Q_D(PcbCamSymbolOval); d->type = PcbCam::Sym_Oval; d->name = iName; QRegularExpression re("^oval([0-9.]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->size = QSizeF(match.captured(1).toDouble()/1000.0, match.captured(2).toDouble()/1000.0); } PcbCamSymbolOval::~PcbCamSymbolOval() { } QPainterPath PcbCamSymbolOval::shape() const { Q_D(const PcbCamSymbolOval); if (d->shape.isEmpty()) { qreal w = d->size.width(); qreal h = d->size.height(); if (w > h) { qreal rad = h / 2.0; d->shape.moveTo(-w/2.0 + rad, -h/2.0); d->shape.lineTo(w/2.0 - rad, -h/2.0); d->shape.arcTo(w/2.0 -rad*2.0, -h/2.0, h, h, 90, -180); d->shape.lineTo(-w/2.0 + rad, h/2.0); d->shape.arcTo(-w/2.0, -h/2.0, h, h, -90, -180); d->shape.closeSubpath(); } else { qreal rad = w/2.0; d->shape.moveTo(w/2.0, -h/2.0 + rad); d->shape.lineTo(w/2.0, h/2.0 - rad); d->shape.arcTo(-w/2.0, h/2.0 - rad*2.0, w, w, 0, -180); d->shape.lineTo(-w/2.0,-h/2.0 + rad); d->shape.arcTo(-w/2.0, -h/2.0, w, w, 180, -180); d->shape.closeSubpath(); } } return d->shape; } QSizeF PcbCamSymbolOval::size() const { Q_D(const PcbCamSymbolOval); return d->size; } /********************* di100x50 *****************/ class PcbCamSymbolDiPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolDi) public: PcbCamSymbolDiPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolDiPrivate() { } QSizeF size ; }; PcbCamSymbolDi::PcbCamSymbolDi(const QString iName) : PcbCamSymbol(*new PcbCamSymbolDiPrivate) { Q_D(PcbCamSymbolDi); d->type = PcbCam::Sym_Di; d->name = iName; QRegularExpression re("^di([0-9.]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->size = QSizeF(match.captured(1).toDouble()/1000.0, match.captured(2).toDouble()/1000.0); } PcbCamSymbolDi::~PcbCamSymbolDi() { } QPainterPath PcbCamSymbolDi::shape() const { Q_D(const PcbCamSymbolDi); if (d->shape.isEmpty()) { qreal w = d->size.width(); qreal h = d->size.height(); qreal x = -w/2.0; qreal y = -h/2.0; qreal wh = w/2.0; qreal hh = h/2.0; d->shape.moveTo(x, y+hh); d->shape.lineTo(x+wh, y); d->shape.lineTo(x+w, y + hh); d->shape.lineTo(x + wh, y + h); d->shape.closeSubpath(); } return d->shape; } QSizeF PcbCamSymbolDi::size() const { Q_D(const PcbCamSymbolDi); return d->size; } /********************* oct100x50x20 *****************/ class PcbCamSymbolOctPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolOct) public: PcbCamSymbolOctPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolOctPrivate() { } qreal width {0.0} ; qreal height {0.0} ; qreal radius {0.0}; }; PcbCamSymbolOct::PcbCamSymbolOct(const QString iName) : PcbCamSymbol(*new PcbCamSymbolOctPrivate) { Q_D(PcbCamSymbolOct); d->type = PcbCam::Sym_Oct; d->name = iName; QRegularExpression re("^oct([0-9.]+)x([0-9.]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->width = match.captured(1).toDouble()/1000.0; d->height = match.captured(2).toDouble()/1000.0; d->radius = match.captured(3).toDouble()/1000.0; } PcbCamSymbolOct::~PcbCamSymbolOct() { } QPainterPath PcbCamSymbolOct::shape() const { Q_D(const PcbCamSymbolOct); if (d->shape.isEmpty()) { qreal x = -d->width/2.0; qreal y = -d->height/2.0; d->shape.moveTo(x, y + d->height - d->radius); d->shape.lineTo(x, y + d->radius); d->shape.lineTo(x + d->radius, y); d->shape.lineTo(x + d->width - d->radius, y); d->shape.lineTo(x + d->width, y + d->radius); d->shape.lineTo(x + d->width, y + d->height - d->radius); d->shape.lineTo(x + d->width - d->radius, y + d->height); d->shape.lineTo(x + d->radius, y + d->height); d->shape.closeSubpath(); } return d->shape; } qreal PcbCamSymbolOct::width() const { Q_D(const PcbCamSymbolOct); return d->width; } qreal PcbCamSymbolOct::height() const { Q_D(const PcbCamSymbolOct); return d->height; } qreal PcbCamSymbolOct::radius() const { Q_D(const PcbCamSymbolOct); return d->radius; } /********************* donut_r100x50 *****************/ class PcbCamSymbolDonutRPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolDonutR) public: PcbCamSymbolDonutRPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolDonutRPrivate() { } qreal outerDiam {0.0} ; qreal innerDiam {0.0} ; }; PcbCamSymbolDonutR::PcbCamSymbolDonutR(const QString iName) : PcbCamSymbol(*new PcbCamSymbolDonutRPrivate) { Q_D(PcbCamSymbolDonutR); d->type = PcbCam::Sym_DonutR; d->name = iName; QRegularExpression re("^donut_r([0-9.]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->outerDiam = match.captured(1).toDouble()/1000.0; d->innerDiam = match.captured(2).toDouble()/1000.0; } PcbCamSymbolDonutR::~PcbCamSymbolDonutR() { } QPainterPath PcbCamSymbolDonutR::shape() const { Q_D(const PcbCamSymbolDonutR); if (d->shape.isEmpty()) { d->shape.addEllipse(-d->outerDiam/2.0, -d->outerDiam/2.0, d->outerDiam, d->outerDiam); d->shape.addEllipse(-d->innerDiam/2.0, -d->innerDiam/2.0, d->innerDiam, d->innerDiam); } return d->shape; } qreal PcbCamSymbolDonutR::outerDiam() const { Q_D(const PcbCamSymbolDonutR); return d->outerDiam; } qreal PcbCamSymbolDonutR::innerDiam() const { Q_D(const PcbCamSymbolDonutR); return d->innerDiam; } /********************* donut_s100x50 *****************/ class PcbCamSymbolDonutSPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolDonutS) public: PcbCamSymbolDonutSPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolDonutSPrivate() { } qreal outerDiam {0.0} ; qreal innerDiam {0.0} ; }; PcbCamSymbolDonutS::PcbCamSymbolDonutS(const QString iName) : PcbCamSymbol(*new PcbCamSymbolDonutSPrivate) { Q_D(PcbCamSymbolDonutS); d->type = PcbCam::Sym_DonutS; d->name = iName; QRegularExpression re("^donut_s([0-9.]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->outerDiam = match.captured(1).toDouble()/1000.0; d->innerDiam = match.captured(2).toDouble()/1000.0; } PcbCamSymbolDonutS::~PcbCamSymbolDonutS() { } QPainterPath PcbCamSymbolDonutS::shape() const { Q_D(const PcbCamSymbolDonutS); if (d->shape.isEmpty()) { d->shape.addRect(-d->outerDiam/2.0, -d->outerDiam/2.0, d->outerDiam, d->outerDiam); d->shape.addRect(-d->innerDiam/2.0, -d->innerDiam/2.0, d->innerDiam, d->innerDiam); } return d->shape; } qreal PcbCamSymbolDonutS::outerDiam() const { Q_D(const PcbCamSymbolDonutS); return d->outerDiam; } qreal PcbCamSymbolDonutS::innerDiam() const { Q_D(const PcbCamSymbolDonutS); return d->innerDiam; } /********************* hex_l100x50x20 *****************/ class PcbCamSymbolHexLPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolHexL) public: PcbCamSymbolHexLPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolHexLPrivate() { } qreal width {0.0} ; qreal height {0.0} ; qreal radius {0.0}; }; PcbCamSymbolHexL::PcbCamSymbolHexL(const QString iName) : PcbCamSymbol(*new PcbCamSymbolHexLPrivate) { Q_D(PcbCamSymbolHexL); d->type = PcbCam::Sym_HexL; d->name = iName; QRegularExpression re("^hex_l([0-9.]+)x([0-9.]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->width = match.captured(1).toDouble()/1000.0; d->height = match.captured(2).toDouble()/1000.0; d->radius = match.captured(3).toDouble()/1000.0; } PcbCamSymbolHexL::~PcbCamSymbolHexL() { } QPainterPath PcbCamSymbolHexL::shape() const { Q_D(const PcbCamSymbolHexL); if (d->shape.isEmpty()) { d->shape.moveTo(-d->width/2.0 + d->radius, -d->height/2.0); d->shape.lineTo(-d->width/2.0, 0); d->shape.lineTo(-d->width/2.0 + d->radius, d->height/2.0); d->shape.lineTo(d->width/2.0 - d->radius, d->height/2.0); d->shape.lineTo(d->width/2.0, 0); d->shape.lineTo(d->width/2.0 - d->radius, -d->height/2.0); d->shape.closeSubpath(); } return d->shape; } qreal PcbCamSymbolHexL::width() const { Q_D(const PcbCamSymbolHexL); return d->width; } qreal PcbCamSymbolHexL::height() const { Q_D(const PcbCamSymbolHexL); return d->height; } qreal PcbCamSymbolHexL::radius() const { Q_D(const PcbCamSymbolHexL); return d->radius; } /********************* hex_s100x50x20 *****************/ class PcbCamSymbolHexSPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolHexS) public: PcbCamSymbolHexSPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolHexSPrivate() { } qreal width {0.0} ; qreal height {0.0} ; qreal radius {0.0}; }; PcbCamSymbolHexS::PcbCamSymbolHexS(const QString iName) : PcbCamSymbol(*new PcbCamSymbolHexSPrivate) { Q_D(PcbCamSymbolHexS); d->type = PcbCam::Sym_HexS; d->name = iName; QRegularExpression re("^hex_s([0-9.]+)x([0-9.]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->width = match.captured(1).toDouble()/1000.0; d->height = match.captured(2).toDouble()/1000.0; d->radius = match.captured(3).toDouble()/1000.0; } PcbCamSymbolHexS::~PcbCamSymbolHexS() { } QPainterPath PcbCamSymbolHexS::shape() const { Q_D(const PcbCamSymbolHexS); if (d->shape.isEmpty()) { d->shape.moveTo(0, -d->height/2.0); d->shape.lineTo(-d->width/2.0, -d->height/2.0 + d->radius); d->shape.lineTo(-d->width/2.0, d->height/2.0 - d->radius); d->shape.lineTo(0, d->height/2.0); d->shape.lineTo(d->width/2.0, d->height/2.0 - d->radius); d->shape.lineTo(d->width/2.0, -d->height/2.0 + d->radius); d->shape.closeSubpath(); } return d->shape; } qreal PcbCamSymbolHexS::width() const { Q_D(const PcbCamSymbolHexS); return d->width; } qreal PcbCamSymbolHexS::height() const { Q_D(const PcbCamSymbolHexS); return d->height; } qreal PcbCamSymbolHexS::radius() const { Q_D(const PcbCamSymbolHexS); return d->radius; } /********************* bfr10 *****************/ class PcbCamSymbolBfrPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolBfr) public: PcbCamSymbolBfrPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolBfrPrivate() { } qreal size {0.0}; }; PcbCamSymbolBfr::PcbCamSymbolBfr(const QString iName) : PcbCamSymbol(*new PcbCamSymbolBfrPrivate) { Q_D(PcbCamSymbolBfr); d->type = PcbCam::Sym_Bfr; d->name = iName; QRegularExpression re("^bfr([0-9.]+)$"); d->size = re.match(d->name).captured(1).toDouble()/1000.0; } PcbCamSymbolBfr::~PcbCamSymbolBfr() { } QPainterPath PcbCamSymbolBfr::shape() const { Q_D(const PcbCamSymbolBfr); if (d->shape.isEmpty()) { d->shape.moveTo(0, 0); d->shape.arcTo(-d->size/2.0, -d->size/2.0, d->size, d->size, 0, 90); d->shape.closeSubpath(); d->shape.moveTo(0, 0); d->shape.arcTo(-d->size/2.0, -d->size/2.0, d->size, d->size, -90, -90); d->shape.closeSubpath(); } return d->shape; } qreal PcbCamSymbolBfr::size() const { Q_D(const PcbCamSymbolBfr); return d->size; } /********************* bfs10 *****************/ class PcbCamSymbolBfsPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolBfs) public: PcbCamSymbolBfsPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolBfsPrivate() { } qreal size {0.0}; }; PcbCamSymbolBfs::PcbCamSymbolBfs(const QString iName) : PcbCamSymbol(*new PcbCamSymbolBfsPrivate) { Q_D(PcbCamSymbolBfs); d->type = PcbCam::Sym_Bfs; d->name = iName; QRegularExpression re("^bfs([0-9.]+)$"); d->size = re.match(d->name).captured(1).toDouble()/1000.0; } PcbCamSymbolBfs::~PcbCamSymbolBfs() { } QPainterPath PcbCamSymbolBfs::shape() const { Q_D(const PcbCamSymbolBfs); if (d->shape.isEmpty()) { d->shape.addRect(0, -d->size/2.0, d->size/2.0, d->size/2.0); d->shape.addRect(-d->size/2.0, 0, d->size/2.0, d->size/2.0); } return d->shape; } qreal PcbCamSymbolBfs::size() const { Q_D(const PcbCamSymbolBfs); return d->size; } /********************* tri10x20 *****************/ class PcbCamSymbolTriPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolTri) public: PcbCamSymbolTriPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolTriPrivate() { } QSizeF size ; }; PcbCamSymbolTri::PcbCamSymbolTri(const QString iName) : PcbCamSymbol(*new PcbCamSymbolTriPrivate) { Q_D(PcbCamSymbolTri); d->type = PcbCam::Sym_Tri; d->name = iName; QRegularExpression re("^tri([0-9.]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->size = QSizeF(match.captured(1).toDouble()/1000.0, match.captured(2).toDouble()/1000.0); } PcbCamSymbolTri::~PcbCamSymbolTri() { } QPainterPath PcbCamSymbolTri::shape() const { Q_D(const PcbCamSymbolTri); if (d->shape.isEmpty()) { qreal w = d->size.width(); qreal h = d->size.height(); d->shape.moveTo(0, h/2.0); d->shape.lineTo(-w/2.0, -h/2.0); d->shape.lineTo(w/2.0, -h/2.0); d->shape.closeSubpath(); } return d->shape; } QSizeF PcbCamSymbolTri::size() const { Q_D(const PcbCamSymbolTri); return d->size; } /********************* orval_h100x20 *****************/ class PcbCamSymbolOvalHPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolOvalH) public: PcbCamSymbolOvalHPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolOvalHPrivate() { } QSizeF size ; }; PcbCamSymbolOvalH::PcbCamSymbolOvalH(const QString iName) : PcbCamSymbol(*new PcbCamSymbolOvalHPrivate) { Q_D(PcbCamSymbolOvalH); d->type = PcbCam::Sym_OvalH; d->name = iName; QRegularExpression re("^oval_h([0-9.]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->size = QSizeF(match.captured(1).toDouble()/1000.0, match.captured(2).toDouble()/1000.0); } PcbCamSymbolOvalH::~PcbCamSymbolOvalH() { } QPainterPath PcbCamSymbolOvalH::shape() const { Q_D(const PcbCamSymbolOvalH); if (d->shape.isEmpty()) { //TODO may have bug qreal w = d->size.width(); qreal h = d->size.height(); d->shape.moveTo(w/2.0 - h, -h/2.0); d->shape.arcTo(w/2.0 - h, -h/2.0, h, h, 90, -180); d->shape.lineTo(-w/2.0, h/2.0); d->shape.lineTo(-w/2.0, -h/2.0); d->shape.closeSubpath(); } return d->shape; } QSizeF PcbCamSymbolOvalH::size() const { Q_D(const PcbCamSymbolOvalH); return d->size; } /********************* thr100x70x30x5x20 *****************/ class PcbCamSymbolThrPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolThr) public: PcbCamSymbolThrPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolThrPrivate() { } qreal outerDiam {0.0} ; qreal innerDiam {0.0} ; qreal startAngle {0.0} ; int numSpokes {1}; qreal spokesGap {0.0}; }; PcbCamSymbolThr::PcbCamSymbolThr(const QString iName) : PcbCamSymbol(*new PcbCamSymbolThrPrivate) { Q_D(PcbCamSymbolThr); d->type = PcbCam::Sym_Thr; d->name = iName; QRegularExpression re("^thr([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->outerDiam = match.captured(1).toDouble()/1000.0; d->innerDiam = match.captured(2).toDouble()/1000.0; d->startAngle = match.captured(3).toDouble(); d->numSpokes = match.captured(4).toInt(); d->spokesGap = match.captured(5).toDouble()/1000.0; } PcbCamSymbolThr::~PcbCamSymbolThr() { } QPainterPath PcbCamSymbolThr::shape() const { Q_D(const PcbCamSymbolThr); if (d->shape.isEmpty()) { qreal lineRadius = (d->outerDiam - d->innerDiam) / 4.0; qreal centerRadius = d->innerDiam/2.0 + lineRadius; qreal x1 = qSqrt(centerRadius*centerRadius - (lineRadius+d->spokesGap/2.0)*(lineRadius+d->spokesGap/2.0)); QPointF p1 = QPointF(x1, lineRadius+d->spokesGap/2.0); qreal angle1 = qAtan2(p1.y(), p1.x()) * 180/M_PI; QPainterPath path0; path0.arcMoveTo(-centerRadius, -centerRadius, 2*centerRadius, 2*centerRadius, angle1); path0.arcTo(-centerRadius, -centerRadius, 2*centerRadius, 2*centerRadius, angle1, 360.0/d->numSpokes - 2*angle1); QPainterPathStroker stroker; stroker.setWidth(lineRadius*2); stroker.setJoinStyle(Qt::RoundJoin); stroker.setCapStyle(Qt::RoundCap); path0 = stroker.createStroke(path0); for (int i = 0; i < d->numSpokes; ++i) { QTransform trans; trans.rotate(d->startAngle + (360.0 / d->numSpokes) * i); d->shape.addPath(trans.map(path0)); } } return d->shape; } qreal PcbCamSymbolThr::outerDiam() const { Q_D(const PcbCamSymbolThr); return d->outerDiam; } qreal PcbCamSymbolThr::innerDiam() const { Q_D(const PcbCamSymbolThr); return d->innerDiam; } qreal PcbCamSymbolThr::startAngle() const { Q_D(const PcbCamSymbolThr); return d->startAngle; } int PcbCamSymbolThr::numSpokes() const { Q_D(const PcbCamSymbolThr); return d->numSpokes; } qreal PcbCamSymbolThr::spokesGap() const { Q_D(const PcbCamSymbolThr); return d->spokesGap; } /********************* ths100x70x30x5x20 *****************/ class PcbCamSymbolThsPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolThs) public: PcbCamSymbolThsPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolThsPrivate() { } qreal outerDiam {0.0} ; qreal innerDiam {0.0} ; qreal startAngle {0.0} ; int numSpokes {1}; qreal spokesGap {0.0}; }; PcbCamSymbolThs::PcbCamSymbolThs(const QString iName) : PcbCamSymbol(*new PcbCamSymbolThsPrivate) { Q_D(PcbCamSymbolThs); d->type = PcbCam::Sym_Ths; d->name = iName; QRegularExpression re("^ths([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->outerDiam = match.captured(1).toDouble()/1000.0; d->innerDiam = match.captured(2).toDouble()/1000.0; d->startAngle = match.captured(3).toDouble(); d->numSpokes = match.captured(4).toInt(); d->spokesGap = match.captured(5).toDouble()/1000.0; } PcbCamSymbolThs::~PcbCamSymbolThs() { } QPainterPath PcbCamSymbolThs::shape() const { Q_D(const PcbCamSymbolThs); if (d->shape.isEmpty()) { qreal pie_angle = 360.0/d->numSpokes; qreal half_inner_gap_angle = (180.0/M_PI) * (qAsin(d->spokesGap/d->innerDiam)); qreal half_outer_gap_angle = (180.0/M_PI) * (qAsin(d->spokesGap/d->outerDiam)); qreal inner_start_angle = d->startAngle + half_inner_gap_angle; qreal inner_pie_angle = pie_angle - 2 * half_inner_gap_angle; qreal outer_start_angle = d->startAngle + half_outer_gap_angle; qreal outer_pie_angle = pie_angle - 2 * half_outer_gap_angle; for (int i = 0; i < d->numSpokes; ++i) { d->shape.arcMoveTo(-d->outerDiam/2.0, -d->outerDiam/2.0, d->outerDiam, d->outerDiam, outer_start_angle); d->shape.arcTo(-d->outerDiam/2.0, -d->outerDiam/2.0, d->outerDiam, d->outerDiam, outer_start_angle, outer_pie_angle); d->shape.arcTo(-d->innerDiam/2.0, -d->innerDiam/2.0, d->innerDiam, d->innerDiam, inner_start_angle + inner_pie_angle, 0); d->shape.arcTo(-d->innerDiam/2.0, -d->innerDiam/2.0, d->innerDiam, d->innerDiam, inner_start_angle + inner_pie_angle, -inner_pie_angle); d->shape.closeSubpath(); inner_start_angle += pie_angle; outer_start_angle += pie_angle; } QTransform trans; trans.scale(1, -1); d->shape = trans.map(d->shape); } return d->shape; } qreal PcbCamSymbolThs::outerDiam() const { Q_D(const PcbCamSymbolThs); return d->outerDiam; } qreal PcbCamSymbolThs::innerDiam() const { Q_D(const PcbCamSymbolThs); return d->innerDiam; } qreal PcbCamSymbolThs::startAngle() const { Q_D(const PcbCamSymbolThs); return d->startAngle; } int PcbCamSymbolThs::numSpokes() const { Q_D(const PcbCamSymbolThs); return d->numSpokes; } qreal PcbCamSymbolThs::spokesGap() const { Q_D(const PcbCamSymbolThs); return d->spokesGap; } /********************* s_ths100x70x30x5x20 *****************/ class PcbCamSymbolSThsPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolSThs) public: PcbCamSymbolSThsPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolSThsPrivate() { } qreal outerDiam {0.0} ; qreal innerDiam {0.0} ; qreal startAngle {0.0} ; int numSpokes {1}; qreal spokesGap {0.0}; }; PcbCamSymbolSThs::PcbCamSymbolSThs(const QString iName) : PcbCamSymbol(*new PcbCamSymbolSThsPrivate) { Q_D(PcbCamSymbolSThs); d->type = PcbCam::Sym_SThs; d->name = iName; QRegularExpression re("^s_ths([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->outerDiam = match.captured(1).toDouble()/1000.0; d->innerDiam = match.captured(2).toDouble()/1000.0; d->startAngle = match.captured(3).toDouble(); d->numSpokes = match.captured(4).toInt(); d->spokesGap = match.captured(5).toDouble()/1000.0; } PcbCamSymbolSThs::~PcbCamSymbolSThs() { } QPainterPath PcbCamSymbolSThs::shape() const { Q_D(const PcbCamSymbolSThs); if (d->shape.isEmpty()) { QPainterPath path; path.addRect(-d->outerDiam/2.0, -d->outerDiam/2.0, d->outerDiam, d->outerDiam); path.addRect(-d->innerDiam/2.0, -d->innerDiam/2.0, d->innerDiam, d->innerDiam); QPainterPath bar; bar.addRect(0, -d->spokesGap/2.0, d->outerDiam + 0.0001, d->spokesGap); QPainterPath sub; QTransform mat; mat.rotate(d->startAngle); qreal angle_div = 360.0 / d->numSpokes; for (int i = 0; i < d->numSpokes; ++i) { sub.addPath(mat.map(bar)); mat.rotate(angle_div); } d->shape = path.subtracted(sub); } return d->shape; } qreal PcbCamSymbolSThs::outerDiam() const { Q_D(const PcbCamSymbolSThs); return d->outerDiam; } qreal PcbCamSymbolSThs::innerDiam() const { Q_D(const PcbCamSymbolSThs); return d->innerDiam; } qreal PcbCamSymbolSThs::startAngle() const { Q_D(const PcbCamSymbolSThs); return d->startAngle; } int PcbCamSymbolSThs::numSpokes() const { Q_D(const PcbCamSymbolSThs); return d->numSpokes; } qreal PcbCamSymbolSThs::spokesGap() const { Q_D(const PcbCamSymbolSThs); return d->spokesGap; } /********************* s_tho100x70x30x5x20 *****************/ class PcbCamSymbolSThoPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolSTho) public: PcbCamSymbolSThoPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolSThoPrivate() { } int sign(qreal val) const { return (val >= 0) + (val < 0) * (-1); } qreal outerDiam {0.0} ; qreal innerDiam {0.0} ; qreal startAngle {0.0} ; int numSpokes {1}; qreal spokesGap {0.0}; }; PcbCamSymbolSTho::PcbCamSymbolSTho(const QString iName) : PcbCamSymbol(*new PcbCamSymbolSThoPrivate) { Q_D(PcbCamSymbolSTho); d->type = PcbCam::Sym_STho; d->name = iName; QRegularExpression re("^s_tho([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->outerDiam = match.captured(1).toDouble()/1000.0; d->innerDiam = match.captured(2).toDouble()/1000.0; d->startAngle = match.captured(3).toDouble(); d->numSpokes = match.captured(4).toInt(); d->spokesGap = match.captured(5).toDouble()/1000.0; } PcbCamSymbolSTho::~PcbCamSymbolSTho() { } QPainterPath PcbCamSymbolSTho::shape() const { Q_D(const PcbCamSymbolSTho); if (d->shape.isEmpty()) { if ((d->numSpokes != 1 && d->numSpokes != 2 && d->numSpokes != 4) || ((int)d->startAngle % 45 != 0)) { //TOP8LOG.error() << "invalid symbol " << d->name; return QPainterPath(); } QPainterPath path; path.addRect(-d->outerDiam/2.0, -d->outerDiam/2.0, d->outerDiam, d->outerDiam); path.addRect(-d->innerDiam/2.0, -d->innerDiam/2.0, d->innerDiam, d->innerDiam); QPainterPath sub; qreal angle_div = 360.0/d->numSpokes; if ((int)d->startAngle % 90 == 0) { QPainterPath bar; bar.addRect(0, -d->spokesGap/2.0, d->outerDiam, d->spokesGap); QTransform mat; mat.rotate(-d->startAngle); for (int i = 0; i < d->numSpokes; ++i) { sub.addPath(mat.map(bar)); mat.rotate(-angle_div); } } else { qreal side = d->spokesGap * qCos(M_PI/4.0) + (d->outerDiam - d->innerDiam)/2.0; qreal offset = (d->outerDiam - side) /2.0; QPainterPath box; box.addRect(-side/2.0, -side/2.0, side, side); for (int i = 0; i < d->numSpokes; ++i) { QTransform mat; mat.translate(offset * d->sign(qCos((d->startAngle + angle_div * i) * (M_PI/180.0))), -offset * d->sign(qSin((d->startAngle + angle_div * i) * (M_PI/180.0)))); sub.addPath(mat.map(box)); } } QTransform mat; mat.scale(1, -1); d->shape = mat.map(path.subtracted(sub)); } return d->shape; } qreal PcbCamSymbolSTho::outerDiam() const { Q_D(const PcbCamSymbolSTho); return d->outerDiam; } qreal PcbCamSymbolSTho::innerDiam() const { Q_D(const PcbCamSymbolSTho); return d->innerDiam; } qreal PcbCamSymbolSTho::startAngle() const { Q_D(const PcbCamSymbolSTho); return d->startAngle; } int PcbCamSymbolSTho::numSpokes() const { Q_D(const PcbCamSymbolSTho); return d->numSpokes; } qreal PcbCamSymbolSTho::spokesGap() const { Q_D(const PcbCamSymbolSTho); return d->spokesGap; } /********************* sr_ths100x70x30x5x20 *****************/ class PcbCamSymbolSrThsPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolSrThs) public: PcbCamSymbolSrThsPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolSrThsPrivate() { } int sign(qreal val) const { return (val >= 0) + (val < 0) * (-1); } qreal outerDiam {0.0} ; qreal innerDiam {0.0} ; qreal startAngle {0.0} ; int numSpokes {1}; qreal spokesGap {0.0}; }; PcbCamSymbolSrThs::PcbCamSymbolSrThs(const QString iName) : PcbCamSymbol(*new PcbCamSymbolSrThsPrivate) { Q_D(PcbCamSymbolSrThs); d->type = PcbCam::Sym_SrThs; d->name = iName; QRegularExpression re("^sr_ths([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->outerDiam = match.captured(1).toDouble()/1000.0; d->innerDiam = match.captured(2).toDouble()/1000.0; d->startAngle = match.captured(3).toDouble(); d->numSpokes = match.captured(4).toInt(); d->spokesGap = match.captured(5).toDouble()/1000.0; } PcbCamSymbolSrThs::~PcbCamSymbolSrThs() { } QPainterPath PcbCamSymbolSrThs::shape() const { Q_D(const PcbCamSymbolSrThs); if (d->shape.isEmpty()) { QPainterPath path; path.addRect(-d->outerDiam/2.0, -d->outerDiam/2.0, d->outerDiam, d->outerDiam); path.addEllipse(-d->innerDiam/2.0, -d->innerDiam/2.0, d->innerDiam, d->innerDiam); QPainterPath bar; bar.addRect(0, -d->spokesGap/2.0, d->outerDiam + 0.0001, d->spokesGap); QPainterPath sub; QTransform mat; mat.rotate(d->startAngle); qreal angle_div = 360.0 / d->numSpokes; for (int i = 0; i < d->numSpokes; ++i) { sub.addPath(mat.map(bar)); mat.rotate(angle_div); } //因为substracted会打段圆弧,造成精度丢失,所以我们放大1000倍来处理; QTransform mat2; mat2.scale(1000, 1000); d->shape = mat2.map(path).subtracted(mat2.map(sub)); QTransform mat3; mat3.scale(0.001, 0.001); d->shape = mat3.map(d->shape); } return d->shape; } qreal PcbCamSymbolSrThs::outerDiam() const { Q_D(const PcbCamSymbolSrThs); return d->outerDiam; } qreal PcbCamSymbolSrThs::innerDiam() const { Q_D(const PcbCamSymbolSrThs); return d->innerDiam; } qreal PcbCamSymbolSrThs::startAngle() const { Q_D(const PcbCamSymbolSrThs); return d->startAngle; } int PcbCamSymbolSrThs::numSpokes() const { Q_D(const PcbCamSymbolSrThs); return d->numSpokes; } qreal PcbCamSymbolSrThs::spokesGap() const { Q_D(const PcbCamSymbolSrThs); return d->spokesGap; } /********************* rc_ths100x70x30x5x20 *****************/ class PcbCamSymbolRcThsPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolRcThs) public: PcbCamSymbolRcThsPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolRcThsPrivate() { } int sign(qreal val) const { return (val >= 0) + (val < 0) * (-1); } qreal width {0.0} ; qreal height {0.0} ; qreal startAngle {0.0} ; int numSpokes {1}; qreal spokesGap {0.0}; qreal airGap {0.0}; }; PcbCamSymbolRcThs::PcbCamSymbolRcThs(const QString iName) : PcbCamSymbol(*new PcbCamSymbolRcThsPrivate) { Q_D(PcbCamSymbolRcThs); d->type = PcbCam::Sym_RcThs; d->name = iName; QRegularExpression re("^rc_ths([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->width = match.captured(1).toDouble()/1000.0; d->height = match.captured(2).toDouble()/1000.0; d->startAngle = match.captured(3).toDouble(); d->numSpokes = match.captured(4).toInt(); d->spokesGap = match.captured(5).toDouble()/1000.0; d->airGap = match.captured(6).toDouble()/1000.0; } PcbCamSymbolRcThs::~PcbCamSymbolRcThs() { } QPainterPath PcbCamSymbolRcThs::shape() const { Q_D(const PcbCamSymbolRcThs); if (d->shape.isEmpty()) { //TODO 当开口数量为3时可能有Bug; QPainterPath path; path.addRect(-d->width / 2, -d->height / 2, d->width, d->height); path.addRect(-d->width / 2 + d->airGap, -d->height / 2 + d->airGap, d->width - 2 * d->airGap, d->height - 2 * d->airGap); QPainterPath bar; bar.addRect(0, -d->spokesGap / 2, d->width, d->spokesGap); QPainterPath sub; qreal angle_div = 360.0 / d->numSpokes; qreal ang = d->startAngle; for (int i = 0; i < d->numSpokes; ++i, ang += angle_div) { QTransform mat; ang = qCeil(ang / 45) * 45.0; if ((int)ang % 90 != 0) { if (d->width > d->height) { mat.translate((d->width - d->height) / 2 * d->sign(qCos((ang) * (M_PI/180.0))), 0); } else { mat.translate(0, -(d->height - d->width) / 2 * d->sign(qSin((ang) * (M_PI/180.0)))); } } mat.rotate(-ang); sub.addPath(mat.map(bar)); } path = path.subtracted(sub); QTransform mat; mat.scale(1, -1); d->shape = mat.map(path); } return d->shape; } qreal PcbCamSymbolRcThs::width() const { Q_D(const PcbCamSymbolRcThs); return d->width; } qreal PcbCamSymbolRcThs::height() const { Q_D(const PcbCamSymbolRcThs); return d->height; } qreal PcbCamSymbolRcThs::startAngle() const { Q_D(const PcbCamSymbolRcThs); return d->startAngle; } int PcbCamSymbolRcThs::numSpokes() const { Q_D(const PcbCamSymbolRcThs); return d->numSpokes; } qreal PcbCamSymbolRcThs::spokesGap() const { Q_D(const PcbCamSymbolRcThs); return d->spokesGap; } qreal PcbCamSymbolRcThs::airGap() const { Q_D(const PcbCamSymbolRcThs); return d->airGap; } /********************* rc_tho100x70x30x5x20 *****************/ class PcbCamSymbolRcThoPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolRcTho) public: PcbCamSymbolRcThoPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolRcThoPrivate() { } int sign(qreal val) const { return (val >= 0) + (val < 0) * (-1); } qreal width {0.0} ; qreal height {0.0} ; qreal startAngle {0.0} ; int numSpokes {1}; qreal spokesGap {0.0}; qreal airGap {0.0}; }; PcbCamSymbolRcTho::PcbCamSymbolRcTho(const QString iName) : PcbCamSymbol(*new PcbCamSymbolRcThoPrivate) { Q_D(PcbCamSymbolRcTho); d->type = PcbCam::Sym_RcTho; d->name = iName; QRegularExpression re("^rc_tho([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9]+)x([0-9.]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->width = match.captured(1).toDouble()/1000.0; d->height = match.captured(2).toDouble()/1000.0; d->startAngle = match.captured(3).toDouble(); d->numSpokes = match.captured(4).toInt(); d->spokesGap = match.captured(5).toDouble()/1000.0; d->airGap = match.captured(6).toDouble()/1000.0; } PcbCamSymbolRcTho::~PcbCamSymbolRcTho() { } QPainterPath PcbCamSymbolRcTho::shape() const { Q_D(const PcbCamSymbolRcTho); if (d->shape.isEmpty()) { QPainterPath path; qreal angle_div = 360.0 / d->numSpokes; QPainterPath sub; QTransform mat; if ((d->numSpokes != 1 && d->numSpokes != 2 && d->numSpokes != 4) || ((int)d->startAngle % 45 != 0)) { //TOP8LOG.error() << "invalid symbol " << d->name; return QPainterPath(); } path.addRect(-d->width / 2, -d->height / 2, d->width, d->height); path.addRect(-d->width / 2 + d->airGap, -d->height / 2 + d->airGap, d->width - 2 * d->airGap, d->height - 2 * d->airGap); if ((int)d->startAngle % 90 == 0) { QPainterPath bar; bar.addRect(0, -d->spokesGap / 2, d->width / 2, d->spokesGap); for (int i = 0; i < d->numSpokes; ++i) { sub.addPath(mat.map(bar)); mat.rotate(-angle_div); } } else { qreal side = d->spokesGap * qCos(M_PI / 4) + d->airGap; qreal offset_w = (d->width - side) / 2, offset_h = (d->height - side) / 2; QPainterPath box; box.addRect(-side / 2, -side / 2, side, side); for (int i = 0; i < d->numSpokes; ++i) { QTransform mat; mat.translate(offset_w * d->sign(qCos((d->startAngle + angle_div * i) * (M_PI/180.0))), -offset_h * d->sign(qSin((d->startAngle + angle_div * i) * (M_PI/180.0)))); sub.addPath(mat.map(box)); } } path = path.subtracted(sub); QTransform mat2; mat2.scale(1, -1); d->shape = mat2.map(path); } return d->shape; } qreal PcbCamSymbolRcTho::width() const { Q_D(const PcbCamSymbolRcTho); return d->width; } qreal PcbCamSymbolRcTho::height() const { Q_D(const PcbCamSymbolRcTho); return d->height; } qreal PcbCamSymbolRcTho::startAngle() const { Q_D(const PcbCamSymbolRcTho); return d->startAngle; } int PcbCamSymbolRcTho::numSpokes() const { Q_D(const PcbCamSymbolRcTho); return d->numSpokes; } qreal PcbCamSymbolRcTho::spokesGap() const { Q_D(const PcbCamSymbolRcTho); return d->spokesGap; } qreal PcbCamSymbolRcTho::airGap() const { Q_D(const PcbCamSymbolRcTho); return d->airGap; } /********************* el10x20 *****************/ class PcbCamSymbolElPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolEl) public: PcbCamSymbolElPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolElPrivate() { } QSizeF size ; }; PcbCamSymbolEl::PcbCamSymbolEl(const QString iName) : PcbCamSymbol(*new PcbCamSymbolElPrivate) { Q_D(PcbCamSymbolEl); d->type = PcbCam::Sym_El; d->name = iName; QRegularExpression re("^el([0-9.]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->size = QSizeF(match.captured(1).toDouble()/1000.0, match.captured(2).toDouble()/1000.0); } PcbCamSymbolEl::~PcbCamSymbolEl() { } QPainterPath PcbCamSymbolEl::shape() const { Q_D(const PcbCamSymbolEl); if (d->shape.isEmpty()) { d->shape.addEllipse(QRectF(-d->size.width()/2.0, -d->size.height()/2.0, d->size.width(), d->size.height())); } return d->shape; } QSizeF PcbCamSymbolEl::size() const { Q_D(const PcbCamSymbolEl); return d->size; } /********************* moire10x10x3x1x100x30 *****************/ class PcbCamSymbolMoirePrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolMoire) public: PcbCamSymbolMoirePrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolMoirePrivate() { } qreal ringWidth {0.0}; qreal ringGap {0.0}; int numRings {1}; qreal lineWidth {0.0}; qreal lineLength {0.0}; qreal lineAngle {0.0}; }; PcbCamSymbolMoire::PcbCamSymbolMoire(const QString iName) : PcbCamSymbol(*new PcbCamSymbolMoirePrivate) { Q_D(PcbCamSymbolMoire); d->type = PcbCam::Sym_Moire; d->name = iName; QRegularExpression re("^moire([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9.]+)x([0-9.]+)$"); QRegularExpressionMatch match = re.match(d->name); d->ringWidth = match.captured(1).toDouble()/1000.0; d->ringGap = match.captured(2).toDouble()/1000.0; d->numRings = match.captured(3).toInt(); d->lineWidth = match.captured(4).toDouble()/1000.0; d->lineLength = match.captured(5).toDouble()/1000.0; d->lineAngle = match.captured(6).toDouble(); } PcbCamSymbolMoire::~PcbCamSymbolMoire() { } QPainterPath PcbCamSymbolMoire::shape() const { Q_D(const PcbCamSymbolMoire); if (d->shape.isEmpty()) { QPainterPath ringpath; ringpath.addEllipse(-d->ringWidth/2.0, -d->ringWidth/2.0, d->ringWidth, d->ringWidth); QPainterPathStroker rstroker; rstroker.setWidth(d->ringWidth); rstroker.setJoinStyle(Qt::RoundJoin); rstroker.setCapStyle(Qt::RoundCap); for (int i = 1; i <= d->numRings; ++i) { qreal rad = d->ringWidth/2.0 + (d->ringGap + d->ringWidth/2.0) * i; QPainterPath p; p.addEllipse(-rad, -rad, rad*2.0, rad*2.0); ringpath.addPath(rstroker.createStroke(p)); } QPainterPath linepath; linepath.moveTo(-d->lineLength/2.0, 0); linepath.lineTo(d->lineLength/2.0, 0); linepath.moveTo(0, -d->lineLength/2.0); linepath.lineTo(0, d->lineLength/2.0); QPainterPathStroker lstroker; lstroker.setWidth(d->lineWidth); lstroker.setJoinStyle(Qt::RoundJoin); lstroker.setCapStyle(Qt::RoundCap); linepath = lstroker.createStroke(linepath); QTransform mat1; mat1.scale(1000, 1000); ringpath = mat1.map(ringpath).simplified(); linepath = mat1.map(linepath).simplified(); QPainterPath path = ringpath.united(linepath); QTransform mat2; mat2.scale(0.001, 0.001); mat2.rotate(-d->lineAngle); d->shape = mat2.map(path); } return d->shape; } qreal PcbCamSymbolMoire::ringWidth() const { Q_D(const PcbCamSymbolMoire); return d->ringWidth; } qreal PcbCamSymbolMoire::ringGap() const { Q_D(const PcbCamSymbolMoire); return d->ringGap; } int PcbCamSymbolMoire::numRings() const { Q_D(const PcbCamSymbolMoire); return d->numRings; } qreal PcbCamSymbolMoire::lineWidth() const { Q_D(const PcbCamSymbolMoire); return d->lineWidth; } qreal PcbCamSymbolMoire::lineLength() const { Q_D(const PcbCamSymbolMoire); return d->lineLength; } qreal PcbCamSymbolMoire::lineAngle() const { Q_D(const PcbCamSymbolMoire); return d->lineAngle; } /********************* user symbol *****************/ class PcbCamSymbolUserPrivate : public PcbCamSymbolPrivate { Q_DECLARE_PUBLIC(PcbCamSymbolUser) public: PcbCamSymbolUserPrivate() : PcbCamSymbolPrivate() { } ~PcbCamSymbolUserPrivate() { } void destoryFeatures() { qDeleteAll(features); features.clear(); } QList<PcbCamFeature *> features; int maxIndex {0}; }; PcbCamSymbolUser::PcbCamSymbolUser(const QString iName) : PcbCamSymbol(*new PcbCamSymbolUserPrivate) { Q_D(PcbCamSymbolUser); d->type = PcbCam::Sym_User; d->name = iName; } PcbCamSymbolUser::~PcbCamSymbolUser() { } QPainterPath PcbCamSymbolUser::shape() const { Q_D(const PcbCamSymbolUser); if (d->shape.isEmpty()) { for (auto feat : d->features) { d->shape.addPath(feat->shape()); } } return d->shape; } QList<PcbCamFeature *> PcbCamSymbolUser::features() const { Q_D(const PcbCamSymbolUser); return d->features; } void PcbCamSymbolUser::clearFeatures() { Q_D(PcbCamSymbolUser); d->destoryFeatures(); d->maxIndex = 0; } void PcbCamSymbolUser::addFeature(PcbCamFeature *iFeature) { Q_D(PcbCamSymbolUser); iFeature->setIndex(++d->maxIndex); d->features.append(iFeature); } void PcbCamSymbolUser::addFeatures(const QList<PcbCamFeature *> &iFeatures) { for (PcbCamFeature *feat : iFeatures) { addFeature(feat); } } void PcbCamSymbolUser::deleteFeature(int iIndex) { Q_D(PcbCamSymbolUser); for (int i = 0; i < d->features.count(); ++i) { PcbCamFeature *feat = d->features[i]; if (feat->index() == iIndex) { d->features.removeAt(i); delete feat; return; } } }