File indexing completed on 2024-06-16 08:27:17

0001 /***************************************************************************
0002  *   Copyright (C) 2004-2005 by David Saxton                               *
0003  *   david@bluehaze.org                                                    *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  ***************************************************************************/
0010 
0011 #include "component.h"
0012 #include "canvasitemparts.h"
0013 #include "circuitdocument.h"
0014 #include "ecnode.h"
0015 #include "itemdocumentdata.h"
0016 #include "node.h"
0017 #include "pin.h"
0018 #include "simulator.h"
0019 
0020 #include "bjt.h"
0021 #include "capacitance.h"
0022 #include "cccs.h"
0023 #include "ccvs.h"
0024 #include "currentsignal.h"
0025 #include "currentsource.h"
0026 #include "diode.h"
0027 #include "inductance.h"
0028 #include "jfet.h"
0029 #include "logic.h"
0030 #include "mosfet.h"
0031 #include "opamp.h"
0032 #include "resistance.h"
0033 #include "switch.h"
0034 #include "vccs.h"
0035 #include "vcvs.h"
0036 #include "voltagepoint.h"
0037 #include "voltagesignal.h"
0038 #include "voltagesource.h"
0039 
0040 #include <QBitArray>
0041 #include <QPainter>
0042 #include <QWidget>
0043 #include <cmath>
0044 
0045 #include <ktlconfig.h>
0046 #include <ktechlab_debug.h>
0047 
0048 // const int dipWidth = 112;    // 2017.10.01 - comment out unused constants
0049 // const int pairSep = 32;
0050 
0051 // Degrees per radian
0052 
0053 Component::Component(ICNDocument *icnDocument, bool newItem, const QString &id)
0054     : CNItem(icnDocument, newItem, id)
0055     , m_angleDegrees(0)
0056     , b_flipped(false)
0057 {
0058     m_pCircuitDocument = dynamic_cast<CircuitDocument *>(icnDocument);
0059 
0060     for (int i = 0; i < 4; ++i) {
0061         m_pPNode[i] = nullptr;
0062         m_pNNode[i] = nullptr;
0063     }
0064 
0065     // Get configuration options
0066     slotUpdateConfiguration();
0067 
0068     // And finally register this :-)
0069     if (icnDocument)
0070         icnDocument->registerItem(this);
0071 }
0072 
0073 Component::~Component()
0074 {
0075     removeElements();
0076     if (!Simulator::isDestroyedSim()) {
0077         Simulator::self()->detachComponent(this);
0078     }
0079 }
0080 
0081 void Component::removeItem()
0082 {
0083     if (b_deleted)
0084         return;
0085     if (!Simulator::isDestroyedSim()) {
0086         Simulator::self()->detachComponent(this);
0087     }
0088     CNItem::removeItem();
0089 }
0090 
0091 void Component::removeElements(bool setPinsInterIndependent)
0092 {
0093     const ElementMapList::iterator end = m_elementMapList.end();
0094     for (ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it) {
0095         Element *e = (*it).e;
0096         if (e) {
0097             emit elementDestroyed(e);
0098             e->componentDeleted();
0099         }
0100     }
0101     m_elementMapList.clear();
0102 
0103     const SwitchList::iterator swEnd = m_switchList.end();
0104     for (SwitchList::iterator it = m_switchList.begin(); it != swEnd; ++it) {
0105         Switch *sw = *it;
0106         if (!sw)
0107             continue;
0108 
0109         emit switchDestroyed(sw);
0110         delete sw;
0111     }
0112     m_switchList.clear();
0113 
0114     if (setPinsInterIndependent)
0115         setAllPinsInterIndependent();
0116 }
0117 
0118 void Component::removeElement(Element *element, bool setPinsInterIndependent)
0119 {
0120     if (!element)
0121         return;
0122 
0123     emit elementDestroyed(element);
0124     element->componentDeleted();
0125 
0126     const ElementMapList::iterator end = m_elementMapList.end();
0127     for (ElementMapList::iterator it = m_elementMapList.begin(); it != end;) {
0128         ElementMapList::iterator next = it;
0129         ++next;
0130 
0131         if ((*it).e == element)
0132             m_elementMapList.erase(it);
0133 
0134         it = next;
0135     }
0136 
0137     if (setPinsInterIndependent)
0138         rebuildPinInterDepedence();
0139 }
0140 
0141 void Component::removeSwitch(Switch *sw)
0142 {
0143     if (!sw)
0144         return;
0145 
0146     emit switchDestroyed(sw);
0147     delete sw;
0148     m_switchList.removeAll(sw);
0149     m_pCircuitDocument->requestAssignCircuits();
0150 }
0151 
0152 void Component::setNodalCurrents()
0153 {
0154     const ElementMapList::iterator end = m_elementMapList.end();
0155     for (ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it) {
0156         ElementMap m = (*it);
0157         for (int i = 0; i < 4; i++) {
0158             if (m.n[i]) {
0159                 m.n[i]->mergeCurrent(m.e->m_cnodeI[i]);
0160             }
0161         }
0162     }
0163 }
0164 
0165 void Component::initPainter(QPainter &p)
0166 {
0167     CNItem::initPainter(p);
0168 
0169     if (!b_flipped && (m_angleDegrees % 360 == 0))
0170         return;
0171 
0172     p.save();
0173 
0174     p.translate(int(x()), int(y()));
0175     if (b_flipped)
0176         p.scale(-1, 1);
0177 
0178     p.rotate(m_angleDegrees);
0179     p.translate(-int(x()), -int(y()));
0180 }
0181 
0182 void Component::deinitPainter(QPainter &p)
0183 {
0184     if (!b_flipped && (m_angleDegrees % 360 == 0))
0185         return;
0186 
0187     p.restore();
0188 }
0189 
0190 void Component::setAngleDegrees(int degrees)
0191 {
0192     if (!p_icnDocument)
0193         return;
0194 
0195     degrees = ((degrees % 360) + 360) % 360;
0196     if (m_angleDegrees == degrees)
0197         return;
0198 
0199     updateConnectorPoints(false);
0200     m_angleDegrees = degrees;
0201     itemPointsChanged();
0202     updateAttachedPositioning();
0203     p_icnDocument->requestRerouteInvalidatedConnectors();
0204 
0205     emit orientationChanged();
0206 }
0207 
0208 void Component::setFlipped(bool flipped)
0209 {
0210     if (!p_icnDocument)
0211         return;
0212 
0213     if (flipped == b_flipped)
0214         return;
0215 
0216     updateConnectorPoints(false);
0217     b_flipped = flipped;
0218     itemPointsChanged();
0219     updateAttachedPositioning();
0220     p_icnDocument->requestRerouteInvalidatedConnectors();
0221 
0222     emit orientationChanged();
0223 }
0224 
0225 void Component::itemPointsChanged()
0226 {
0227     QPolygon transformedPoints = transMatrix(m_angleDegrees, b_flipped, 0, 0, false).map(m_itemPoints);
0228     //  transformedPoints.translate( int(x()), int(y()) );
0229     setPoints(transformedPoints);
0230 }
0231 
0232 void Component::restoreFromItemData(const ItemData &itemData)
0233 {
0234     CNItem::restoreFromItemData(itemData);
0235 
0236     setAngleDegrees(int(itemData.angleDegrees));
0237     setFlipped(itemData.flipped);
0238 }
0239 
0240 ItemData Component::itemData() const
0241 {
0242     ItemData itemData = CNItem::itemData();
0243     itemData.angleDegrees = m_angleDegrees;
0244     itemData.flipped = b_flipped;
0245     return itemData;
0246 }
0247 
0248 QTransform Component::transMatrix(int angleDegrees, bool flipped, int x, int y, bool inverse)
0249 {
0250     QTransform m;
0251     m.translate(x, y);
0252     if (inverse) {
0253         m.rotate(-angleDegrees);
0254         if (flipped)
0255             m.scale(-1, 1);
0256     } else {
0257         if (flipped)
0258             m.scale(-1, 1);
0259         m.rotate(angleDegrees);
0260     }
0261     m.translate(-x, -y);
0262     // m.setTransformationMode( QMatrix::Areas ); // TODO find a replacement
0263     return m;
0264 }
0265 
0266 void Component::finishedCreation()
0267 {
0268     CNItem::finishedCreation();
0269     updateAttachedPositioning();
0270 }
0271 
0272 void Component::updateAttachedPositioning()
0273 {
0274     const double RPD = M_PI / 180.0;
0275 
0276     if (b_deleted || !m_bDoneCreation)
0277         return;
0278 
0279     // BEGIN Transform the nodes
0280     const NodeInfoMap::iterator end = m_nodeMap.end();
0281     for (NodeInfoMap::iterator it = m_nodeMap.begin(); it != end; ++it) {
0282         if (!it.value().node)
0283             qCCritical(KTL_LOG) << "Node in nodemap is null";
0284         else {
0285             int nx = int((std::cos(m_angleDegrees * RPD) * it.value().x) - (std::sin(m_angleDegrees * RPD) * it.value().y));
0286             int ny = int((std::sin(m_angleDegrees * RPD) * it.value().x) + (std::cos(m_angleDegrees * RPD) * it.value().y));
0287 
0288             if (b_flipped)
0289                 nx = -nx;
0290 
0291 #define round_8(x) (((x) > 0) ? int(((x) + 4) / 8) * 8 : int(((x)-4) / 8) * 8)
0292             nx = round_8(nx);
0293             ny = round_8(ny);
0294 #undef round_8
0295 
0296             int newDir = (((m_angleDegrees + it.value().orientation) % 360) + 360) % 360;
0297             if (b_flipped)
0298                 newDir = (((180 - newDir) % 360) + 360) % 360;
0299 
0300             it.value().node->move(nx + x(), ny + y());
0301             it.value().node->setOrientation(newDir);
0302         }
0303     }
0304     // END Transform the nodes
0305 
0306     // BEGIN Transform the GuiParts
0307     QTransform m;
0308 
0309     if (b_flipped)
0310         m.scale(-1, 1);
0311     m.rotate(m_angleDegrees);
0312     // m.setTransformationMode( QMatrix::Areas ); // TODO find a replacement
0313 
0314     const TextMap::iterator textMapEnd = m_textMap.end();
0315     for (TextMap::iterator it = m_textMap.begin(); it != textMapEnd; ++it) {
0316         QRect newPos = m.mapRect(it.value()->recommendedRect());
0317         it.value()->move(newPos.x() + x(), newPos.y() + y());
0318         it.value()->setGuiPartSize(newPos.width(), newPos.height());
0319         it.value()->setAngleDegrees(m_angleDegrees);
0320     }
0321     const WidgetMap::iterator widgetMapEnd = m_widgetMap.end();
0322     for (WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it) {
0323         QRect newPos = m.mapRect(it.value()->recommendedRect());
0324         it.value()->move(newPos.x() + x(), newPos.y() + y());
0325         it.value()->setGuiPartSize(newPos.width(), newPos.height());
0326         it.value()->setAngleDegrees(m_angleDegrees);
0327     }
0328     // END Transform the GuiParts
0329 }
0330 
0331 void Component::drawPortShape(QPainter &p)
0332 {
0333     int h = height();
0334     int w = width() - 1;
0335     int _x = int(x() + offsetX());
0336     int _y = int(y() + offsetY());
0337 
0338     double roundSize = 8;
0339     double slantIndent = 8;
0340 
0341     const double DPR = 180.0 / M_PI;
0342     double inner = std::atan(h / slantIndent); // Angle for slight corner
0343     double outer = M_PI - inner;               // Angle for sharp corner
0344 
0345     int inner16 = int(16 * inner * DPR);
0346     int outer16 = int(16 * outer * DPR);
0347 
0348     p.save();
0349     p.setPen(Qt::NoPen);
0350     p.drawPolygon(areaPoints());
0351     p.restore();
0352 
0353     initPainter(p);
0354 
0355     // Left line
0356     p.drawLine(int(_x), int(_y + roundSize / 2), int(_x), int(_y + h - roundSize / 2));
0357 
0358     // Right line
0359     p.drawLine(int(_x + w), int(_y - slantIndent + h - roundSize / 2), int(_x + w), int(_y + slantIndent + roundSize / 2));
0360 
0361     // Bottom line
0362     p.drawLine(
0363         int(_x + (1 - std::cos(outer)) * (roundSize / 2)), int(_y + h + (std::sin(outer) - 1) * (roundSize / 2)), int(_x + w + (std::cos(inner) - 1) * (roundSize / 2)), int(_y + h - slantIndent + (std::sin(inner) - 1) * (roundSize / 2)));
0364 
0365     // Top line
0366     p.drawLine(int(_x + w + (std::cos(outer) - 1) * (roundSize / 2)), int(_y + slantIndent + (1 - std::sin(inner)) * (roundSize / 2)), int(_x + (1 - std::cos(inner)) * (roundSize / 2)), int(_y + (1 - std::sin(outer)) * (roundSize / 2)));
0367 
0368     // Top left
0369     p.drawArc(int(_x), int(_y), int(roundSize), int(roundSize), 90 * 16, outer16);
0370 
0371     // Bottom left
0372     p.drawArc(int(_x), int(_y + h - roundSize), int(roundSize), int(roundSize), 180 * 16, outer16);
0373 
0374     // Top right
0375     p.drawArc(int(_x + w - roundSize), int(_y + slantIndent), int(roundSize), int(roundSize), 0, inner16);
0376 
0377     // Bottom right
0378     p.drawArc(int(_x + w - roundSize), int(_y - slantIndent + h - roundSize), int(roundSize), int(roundSize), 270 * 16, inner16);
0379 
0380     deinitPainter(p);
0381 }
0382 
0383 void Component::initDIP(const QStringList &pins)
0384 {
0385     const int numPins = pins.size();
0386     const int numSide = numPins / 2 + numPins % 2;
0387 
0388     // Pins along left
0389     for (int i = 0; i < numSide; i++) {
0390         if (!pins[i].isEmpty()) {
0391             const int nodeX = -8 + offsetX();
0392             const int nodeY = (i + 1) * 16 + offsetY();
0393             ECNode *node = ecNodeWithID(pins[i]);
0394             if (node) {
0395                 m_nodeMap[pins[i]].x = nodeX;
0396                 m_nodeMap[pins[i]].y = nodeY;
0397                 m_nodeMap[pins[i]].orientation = 0;
0398             } else
0399                 createPin(nodeX, nodeY, 0, pins[i]);
0400         }
0401     }
0402     // Pins along right
0403     for (int i = numSide; i < numPins; i++) {
0404         if (!pins[i].isEmpty()) {
0405             const int nodeX = width() + 8 + offsetX();
0406             const int nodeY = (2 * numSide - i) * 16 + offsetY();
0407             ECNode *node = ecNodeWithID(pins[i]);
0408             if (node) {
0409                 m_nodeMap[pins[i]].x = nodeX;
0410                 m_nodeMap[pins[i]].y = nodeY;
0411                 m_nodeMap[pins[i]].orientation = 180;
0412             } else
0413                 createPin(nodeX, nodeY, 180, pins[i]);
0414         }
0415     }
0416 
0417     updateAttachedPositioning();
0418 }
0419 
0420 void Component::initDIPSymbol(const QStringList &pins, int _width)
0421 {
0422     const int numPins = pins.size();
0423     const int numSide = numPins / 2 + numPins % 2;
0424 
0425     setSize(-(_width - (_width % 16)) / 2, -(numSide + 1) * 8, _width, (numSide + 1) * 16, true);
0426 
0427     // 2015.01.11 - do not use painter
0428     //     QWidget tmpWidget;
0429     //     //tmpWidget.setAttribute(Qt::WA_PaintOutsidePaintEvent, true); // note: add this if needed
0430     //     //QPainter p(&tmpWidget);
0431     //     QPainter p;
0432     //     const bool isSuccess = p.begin(&tmpWidget);
0433     //     if (!isSuccess) {
0434     //         qCWarning(KTL_LOG) << " painter not active";
0435     //     }
0436 
0437     // p.setFont( font() ); // 2015.01.11 - do not use painter
0438     QFontMetrics fontMetrics(font());
0439 
0440     // Pins along left
0441     for (int i = 0; i < numSide; i++) {
0442         if (!pins[i].isEmpty()) {
0443             const QString text = pins.at(i);
0444 
0445             const int _top = (i + 1) * 16 - 8 + offsetY();
0446             const int _width = width() / 2 - 6;
0447             const int _left = 6 + offsetX();
0448             const int _height = 16;
0449 
0450             // QRect br = p.boundingRect( QRect( _left, _top, _width, _height ), Qt::AlignLeft, text ); // 2015.01.11 - do not use painter
0451             QRect br = fontMetrics.boundingRect(QRect(_left, _top, _width, _height), Qt::AlignLeft, text);
0452 
0453             addDisplayText(text, br, text);
0454         }
0455     }
0456     // Pins along right
0457     for (int i = numSide; i < numPins; i++) {
0458         if (!pins[i].isEmpty()) {
0459             const QString text = pins.at(i);
0460 
0461             const int _top = (2 * numSide - i) * 16 - 8 + offsetY();
0462             const int _width = width() / 2 - 6;
0463             const int _left = (width() / 2) + offsetX();
0464             const int _height = 16;
0465 
0466             // QRect br = p.boundingRect( QRect( _left, _top, _width, _height ), Qt::AlignRight, text ); // 2015.01.11 - do not use painter
0467             QRect br = fontMetrics.boundingRect(QRect(_left, _top, _width, _height), Qt::AlignLeft, text);
0468             addDisplayText(text, br, text);
0469         }
0470     }
0471 
0472     updateAttachedPositioning();
0473 }
0474 
0475 void Component::init1PinLeft(int h1)
0476 {
0477     if (h1 == -1)
0478         h1 = offsetY() + height() / 2;
0479 
0480     m_pNNode[0] = createPin(offsetX() - 8, h1, 0, "n1");
0481 }
0482 
0483 void Component::init2PinLeft(int h1, int h2)
0484 {
0485     if (h1 == -1)
0486         h1 = offsetY() + 8;
0487     if (h2 == -1)
0488         h2 = offsetY() + height() - 8;
0489 
0490     m_pNNode[0] = createPin(offsetX() - 8, h1, 0, "n1");
0491     m_pNNode[1] = createPin(offsetX() - 8, h2, 0, "n2");
0492 }
0493 
0494 void Component::init3PinLeft(int h1, int h2, int h3)
0495 {
0496     if (h1 == -1)
0497         h1 = offsetY() + 8;
0498     if (h2 == -1)
0499         h2 = offsetY() + height() / 2;
0500     if (h3 == -1)
0501         h3 = offsetY() + height() - 8;
0502 
0503     m_pNNode[0] = createPin(offsetX() - 8, h1, 0, "n1");
0504     m_pNNode[1] = createPin(offsetX() - 8, h2, 0, "n2");
0505     m_pNNode[2] = createPin(offsetX() - 8, h3, 0, "n3");
0506 }
0507 
0508 void Component::init4PinLeft(int h1, int h2, int h3, int h4)
0509 {
0510     if (h1 == -1)
0511         h1 = offsetY() + 8;
0512     if (h2 == -1)
0513         h2 = offsetY() + 24;
0514     if (h3 == -1)
0515         h3 = offsetY() + height() - 24;
0516     if (h4 == -1)
0517         h4 = offsetY() + height() - 8;
0518 
0519     m_pNNode[0] = createPin(offsetX() - 8, h1, 0, "n1");
0520     m_pNNode[1] = createPin(offsetX() - 8, h2, 0, "n2");
0521     m_pNNode[2] = createPin(offsetX() - 8, h3, 0, "n3");
0522     m_pNNode[3] = createPin(offsetX() - 8, h4, 0, "n4");
0523 }
0524 
0525 void Component::init1PinRight(int h1)
0526 {
0527     if (h1 == -1)
0528         h1 = offsetY() + height() / 2;
0529 
0530     m_pPNode[0] = createPin(offsetX() + width() + 8, h1, 180, "p1");
0531 }
0532 
0533 void Component::init2PinRight(int h1, int h2)
0534 {
0535     if (h1 == -1)
0536         h1 = offsetY() + 8;
0537     if (h2 == -1)
0538         h2 = offsetY() + height() - 8;
0539 
0540     m_pPNode[0] = createPin(offsetX() + width() + 8, h1, 180, "p1");
0541     m_pPNode[1] = createPin(offsetX() + width() + 8, h2, 180, "p2");
0542 }
0543 
0544 void Component::init3PinRight(int h1, int h2, int h3)
0545 {
0546     if (h1 == -1)
0547         h1 = offsetY() + 8;
0548     if (h2 == -1)
0549         h2 = offsetY() + height() / 2;
0550     if (h3 == -1)
0551         h3 = offsetY() + height() - 8;
0552 
0553     m_pPNode[0] = createPin(offsetX() + width() + 8, h1, 180, "p1");
0554     m_pPNode[1] = createPin(offsetX() + width() + 8, h2, 180, "p2");
0555     m_pPNode[2] = createPin(offsetX() + width() + 8, h3, 180, "p3");
0556 }
0557 
0558 void Component::init4PinRight(int h1, int h2, int h3, int h4)
0559 {
0560     if (h1 == -1)
0561         h1 = offsetY() + 8;
0562     if (h2 == -1)
0563         h2 = offsetY() + 24;
0564     if (h3 == -1)
0565         h3 = offsetY() + height() - 24;
0566     if (h4 == -1)
0567         h4 = offsetY() + height() - 8;
0568 
0569     m_pPNode[0] = createPin(offsetX() + width() + 8, h1, 180, "p1");
0570     m_pPNode[1] = createPin(offsetX() + width() + 8, h2, 180, "p2");
0571     m_pPNode[2] = createPin(offsetX() + width() + 8, h3, 180, "p3");
0572     m_pPNode[3] = createPin(offsetX() + width() + 8, h4, 180, "p4");
0573 }
0574 
0575 ECNode *Component::ecNodeWithID(const QString &ecNodeId)
0576 {
0577     if (!p_icnDocument) {
0578         //      qCDebug(KTL_LOG) << "Warning: ecNodeWithID("<<ecNodeId<<") does not exist";
0579         return createPin(0, 0, 0, ecNodeId);
0580     }
0581 
0582     return dynamic_cast<ECNode *>(p_icnDocument->nodeWithID(nodeId(ecNodeId)));
0583 }
0584 
0585 void Component::slotUpdateConfiguration()
0586 {
0587     const LogicConfig logicConfig = LogicIn::getConfig();
0588 
0589     const ElementMapList::iterator end = m_elementMapList.end();
0590     for (ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it) {
0591         if (LogicIn *logicIn = dynamic_cast<LogicIn *>((*it).e))
0592             logicIn->setLogic(logicConfig);
0593     }
0594 }
0595 
0596 BJT *Component::createBJT(ECNode *c, ECNode *b, ECNode *e, bool isNPN)
0597 {
0598     return createBJT(c->pin(), b->pin(), e->pin(), isNPN);
0599 }
0600 
0601 Capacitance *Component::createCapacitance(ECNode *n0, ECNode *n1, double capacitance)
0602 {
0603     return createCapacitance(n0->pin(), n1->pin(), capacitance);
0604 }
0605 
0606 CCCS *Component::createCCCS(ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain)
0607 {
0608     return createCCCS(n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain);
0609 }
0610 
0611 CCVS *Component::createCCVS(ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain)
0612 {
0613     return createCCVS(n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain);
0614 }
0615 
0616 CurrentSignal *Component::createCurrentSignal(ECNode *n0, ECNode *n1, double current)
0617 {
0618     return createCurrentSignal(n0->pin(), n1->pin(), current);
0619 }
0620 
0621 CurrentSource *Component::createCurrentSource(ECNode *n0, ECNode *n1, double current)
0622 {
0623     return createCurrentSource(n0->pin(), n1->pin(), current);
0624 }
0625 
0626 Diode *Component::createDiode(ECNode *n0, ECNode *n1)
0627 {
0628     return createDiode(n0->pin(), n1->pin());
0629 }
0630 
0631 JFET *Component::createJFET(ECNode *D, ECNode *G, ECNode *S, int JFET_type)
0632 {
0633     return createJFET(D->pin(), G->pin(), S->pin(), JFET_type);
0634 }
0635 
0636 Inductance *Component::createInductance(ECNode *n0, ECNode *n1, double inductance)
0637 {
0638     return createInductance(n0->pin(), n1->pin(), inductance);
0639 }
0640 
0641 LogicIn *Component::createLogicIn(ECNode *node)
0642 {
0643     return createLogicIn(node->pin());
0644 }
0645 
0646 LogicOut *Component::createLogicOut(ECNode *node, bool isHigh)
0647 {
0648     return createLogicOut(node->pin(), isHigh);
0649 }
0650 
0651 MOSFET *Component::createMOSFET(ECNode *D, ECNode *G, ECNode *S, ECNode *B, int MOSFET_type)
0652 {
0653     return createMOSFET(D->pin(), G->pin(), S->pin(), B ? B->pin() : nullptr, MOSFET_type);
0654 }
0655 
0656 OpAmp *Component::createOpAmp(ECNode *nonInverting, ECNode *out, ECNode *inverting)
0657 {
0658     return createOpAmp(nonInverting->pin(), out->pin(), inverting->pin());
0659 }
0660 
0661 Resistance *Component::createResistance(ECNode *n0, ECNode *n1, double resistance)
0662 {
0663     return createResistance(n0->pin(), n1->pin(), resistance);
0664 }
0665 
0666 Switch *Component::createSwitch(ECNode *n0, ECNode *n1, bool open)
0667 {
0668     return createSwitch(n0->pin(), n1->pin(), open);
0669 }
0670 
0671 VCCS *Component::createVCCS(ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain)
0672 {
0673     return createVCCS(n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain);
0674 }
0675 
0676 VCVS *Component::createVCVS(ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain)
0677 {
0678     return createVCVS(n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain);
0679 }
0680 
0681 VoltagePoint *Component::createVoltagePoint(ECNode *n0, double voltage)
0682 {
0683     return createVoltagePoint(n0->pin(), voltage);
0684 }
0685 
0686 VoltageSignal *Component::createVoltageSignal(ECNode *n0, ECNode *n1, double voltage)
0687 {
0688     return createVoltageSignal(n0->pin(), n1->pin(), voltage);
0689 }
0690 
0691 VoltageSource *Component::createVoltageSource(ECNode *n0, ECNode *n1, double voltage)
0692 {
0693     return createVoltageSource(n0->pin(), n1->pin(), voltage);
0694 }
0695 
0696 BJT *Component::createBJT(Pin *cN, Pin *bN, Pin *eN, bool isNPN)
0697 {
0698     BJT *e = new BJT(isNPN);
0699 
0700     QList<Pin *> pins;
0701     pins << bN << cN << eN;
0702 
0703     ElementMapList::iterator it = handleElement(e, pins);
0704     setInterDependent(it, pins);
0705     return e;
0706 }
0707 
0708 Capacitance *Component::createCapacitance(Pin *n0, Pin *n1, double capacitance)
0709 {
0710     Capacitance *e = new Capacitance(capacitance, LINEAR_UPDATE_PERIOD);
0711 
0712     QList<Pin *> pins;
0713     pins << n0 << n1;
0714 
0715     ElementMapList::iterator it = handleElement(e, pins);
0716     setInterDependent(it, pins);
0717     return e;
0718 }
0719 
0720 CCCS *Component::createCCCS(Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain)
0721 {
0722     CCCS *e = new CCCS(gain);
0723 
0724     QList<Pin *> pins;
0725     pins << n0 << n1 << n2 << n3;
0726 
0727     ElementMapList::iterator it = handleElement(e, pins);
0728     setInterDependent(it, pins);
0729     return e;
0730 }
0731 
0732 CCVS *Component::createCCVS(Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain)
0733 {
0734     CCVS *e = new CCVS(gain);
0735 
0736     QList<Pin *> pins;
0737     pins << n0 << n1 << n2 << n3;
0738 
0739     ElementMapList::iterator it = handleElement(e, pins);
0740     setInterCircuitDependent(it, pins);
0741 
0742     pins.clear();
0743     pins << n0 << n1;
0744     setInterGroundDependent(it, pins);
0745 
0746     pins.clear();
0747     pins << n2 << n3;
0748     setInterGroundDependent(it, pins);
0749 
0750     return e;
0751 }
0752 
0753 CurrentSignal *Component::createCurrentSignal(Pin *n0, Pin *n1, double current)
0754 {
0755     CurrentSignal *e = new CurrentSignal(LINEAR_UPDATE_PERIOD, current);
0756 
0757     QList<Pin *> pins;
0758     pins << n0 << n1;
0759 
0760     ElementMapList::iterator it = handleElement(e, pins);
0761     setInterDependent(it, pins);
0762     return e;
0763 }
0764 
0765 CurrentSource *Component::createCurrentSource(Pin *n0, Pin *n1, double current)
0766 {
0767     CurrentSource *e = new CurrentSource(current);
0768 
0769     QList<Pin *> pins;
0770     pins << n0 << n1;
0771 
0772     ElementMapList::iterator it = handleElement(e, pins);
0773     setInterDependent(it, pins);
0774     return e;
0775 }
0776 
0777 Diode *Component::createDiode(Pin *n0, Pin *n1)
0778 {
0779     Diode *e = new Diode();
0780 
0781     QList<Pin *> pins;
0782     pins << n0 << n1;
0783 
0784     ElementMapList::iterator it = handleElement(e, pins);
0785     setInterDependent(it, pins);
0786     return e;
0787 }
0788 
0789 JFET *Component::createJFET(Pin *D, Pin *G, Pin *S, int JFET_type)
0790 {
0791     JFET *e = new JFET(JFET::JFET_type(JFET_type));
0792 
0793     QList<Pin *> pins;
0794     pins << D << G << S;
0795 
0796     ElementMapList::iterator it = handleElement(e, pins);
0797     setInterDependent(it, pins);
0798     return e;
0799 }
0800 
0801 Inductance *Component::createInductance(Pin *n0, Pin *n1, double inductance)
0802 {
0803     Inductance *e = new Inductance(inductance, LINEAR_UPDATE_PERIOD);
0804 
0805     QList<Pin *> pins;
0806     pins << n0 << n1;
0807 
0808     ElementMapList::iterator it = handleElement(e, pins);
0809     setInterDependent(it, pins);
0810     return e;
0811 }
0812 
0813 LogicIn *Component::createLogicIn(Pin *node)
0814 {
0815     LogicIn *e = new LogicIn(LogicIn::getConfig());
0816 
0817     QList<Pin *> pins;
0818     pins << node;
0819 
0820     /*ElementMapList::iterator it = */ handleElement(e, pins);
0821     return e;
0822 }
0823 
0824 LogicOut *Component::createLogicOut(Pin *node, bool isHigh)
0825 {
0826     LogicOut *e = new LogicOut(LogicIn::getConfig(), isHigh);
0827 
0828     QList<Pin *> pins;
0829     pins << node;
0830 
0831     ElementMapList::iterator it = handleElement(e, pins);
0832     setInterDependent(it, pins);
0833     return e;
0834 }
0835 
0836 MOSFET *Component::createMOSFET(Pin *D, Pin *G, Pin *S, Pin *B, int MOSFET_type)
0837 {
0838     MOSFET *e = new MOSFET(MOSFET::MOSFET_type(MOSFET_type));
0839 
0840     QList<Pin *> pins;
0841     pins << D << G << S << B;
0842 
0843     /// \todo remove the following line removing body if null
0844     pins.removeAll(nullptr);
0845 
0846     ElementMapList::iterator it = handleElement(e, pins);
0847     setInterDependent(it, pins);
0848     return e;
0849 }
0850 
0851 OpAmp *Component::createOpAmp(Pin *nonInverting, Pin *inverting, Pin *out)
0852 {
0853     OpAmp *e = new OpAmp();
0854 
0855     QList<Pin *> pins;
0856     pins << nonInverting << inverting << out;
0857 
0858     ElementMapList::iterator it = handleElement(e, pins);
0859     setInterDependent(it, pins);
0860     return e;
0861 }
0862 
0863 Resistance *Component::createResistance(Pin *n0, Pin *n1, double resistance)
0864 {
0865     Resistance *e = new Resistance(resistance);
0866 
0867     QList<Pin *> pins;
0868     pins << n0 << n1;
0869 
0870     ElementMapList::iterator it = handleElement(e, pins);
0871     setInterDependent(it, pins);
0872     return e;
0873 }
0874 
0875 Switch *Component::createSwitch(Pin *n0, Pin *n1, bool open)
0876 {
0877     // Note that a Switch is not really an element (although in many cases it
0878     // behaves very much like one).
0879 
0880     Switch *e = new Switch(this, n0, n1, open ? Switch::Open : Switch::Closed);
0881     m_switchList.append(e);
0882     n0->addSwitch(e);
0883     n1->addSwitch(e);
0884     emit switchCreated(e);
0885     return e;
0886 }
0887 
0888 VCCS *Component::createVCCS(Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain)
0889 {
0890     VCCS *e = new VCCS(gain);
0891 
0892     QList<Pin *> pins;
0893     pins << n0 << n1 << n2 << n3;
0894 
0895     ElementMapList::iterator it = handleElement(e, pins);
0896     setInterDependent(it, pins);
0897     return e;
0898 }
0899 
0900 VCVS *Component::createVCVS(Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain)
0901 {
0902     VCVS *e = new VCVS(gain);
0903 
0904     QList<Pin *> pins;
0905     pins << n0 << n1 << n2 << n3;
0906 
0907     ElementMapList::iterator it = handleElement(e, pins);
0908     setInterCircuitDependent(it, pins);
0909 
0910     pins.clear();
0911     pins << n0 << n1;
0912     setInterGroundDependent(it, pins);
0913 
0914     pins.clear();
0915     pins << n2 << n3;
0916     setInterGroundDependent(it, pins);
0917     return e;
0918 }
0919 
0920 VoltagePoint *Component::createVoltagePoint(Pin *n0, double voltage)
0921 {
0922     VoltagePoint *e = new VoltagePoint(voltage);
0923 
0924     QList<Pin *> pins;
0925     pins << n0;
0926 
0927     ElementMapList::iterator it = handleElement(e, pins);
0928     setInterDependent(it, pins);
0929     return e;
0930 }
0931 
0932 VoltageSignal *Component::createVoltageSignal(Pin *n0, Pin *n1, double voltage)
0933 {
0934     VoltageSignal *e = new VoltageSignal(LINEAR_UPDATE_PERIOD, voltage);
0935 
0936     QList<Pin *> pins;
0937     pins << n0 << n1;
0938 
0939     ElementMapList::iterator it = handleElement(e, pins);
0940     setInterDependent(it, pins);
0941     return e;
0942 }
0943 
0944 VoltageSource *Component::createVoltageSource(Pin *n0, Pin *n1, double voltage)
0945 {
0946     VoltageSource *e = new VoltageSource(voltage);
0947 
0948     QList<Pin *> pins;
0949     pins << n0 << n1;
0950 
0951     ElementMapList::iterator it = handleElement(e, pins);
0952     setInterDependent(it, pins);
0953     return e;
0954 }
0955 
0956 ElementMapList::iterator Component::handleElement(Element *e, const QList<Pin *> &pins)
0957 {
0958     if (!e)
0959         return m_elementMapList.end();
0960 
0961     ElementMap em;
0962     em.e = e;
0963     int at = 0;
0964     QList<Pin *>::ConstIterator end = pins.end();
0965     for (QList<Pin *>::ConstIterator it = pins.begin(); it != end; ++it) {
0966         (*it)->addElement(e);
0967         em.n[at++] = *it;
0968     }
0969 
0970     // ElementMapList::iterator it = m_elementMapList.append(em);
0971     ElementMapList::iterator it = m_elementMapList.insert(m_elementMapList.end(), em);
0972 
0973     emit elementCreated(e);
0974     return it;
0975 }
0976 
0977 void Component::setInterDependent(ElementMapList::iterator it, const QList<Pin *> &pins)
0978 {
0979     setInterCircuitDependent(it, pins);
0980     setInterGroundDependent(it, pins);
0981 }
0982 
0983 void Component::setInterCircuitDependent(ElementMapList::iterator it, const QList<Pin *> &pins)
0984 {
0985     QList<Pin *>::ConstIterator end = pins.end();
0986     for (QList<Pin *>::ConstIterator it1 = pins.begin(); it1 != end; ++it1) {
0987         for (QList<Pin *>::ConstIterator it2 = pins.begin(); it2 != end; ++it2) {
0988             (*it1)->addCircuitDependentPin(*it2);
0989         }
0990     }
0991 
0992     (*it).interCircuitDependent.append(pins);
0993 }
0994 
0995 void Component::setInterGroundDependent(ElementMapList::iterator it, const QList<Pin *> &pins)
0996 {
0997     QList<Pin *>::ConstIterator end = pins.end();
0998     for (QList<Pin *>::ConstIterator it1 = pins.begin(); it1 != end; ++it1) {
0999         for (QList<Pin *>::ConstIterator it2 = pins.begin(); it2 != end; ++it2) {
1000             (*it1)->addGroundDependentPin(*it2);
1001         }
1002     }
1003 
1004     (*it).interGroundDependent.append(pins);
1005 }
1006 
1007 void Component::rebuildPinInterDepedence()
1008 {
1009     setAllPinsInterIndependent();
1010 
1011     // Rebuild dependencies
1012     ElementMapList::iterator emlEnd = m_elementMapList.end();
1013     for (ElementMapList::iterator it = m_elementMapList.begin(); it != emlEnd; ++it) {
1014         // Many copies of the pin lists as these will be affected when we call setInter*Dependent
1015         PinListList list = (*it).interCircuitDependent;
1016 
1017         PinListList::iterator depEnd = list.end();
1018         for (PinListList::iterator depIt = list.begin(); depIt != depEnd; ++depIt)
1019             setInterCircuitDependent(it, *depIt);
1020 
1021         list = (*it).interGroundDependent;
1022 
1023         depEnd = list.end();
1024         for (PinListList::iterator depIt = list.begin(); depIt != depEnd; ++depIt)
1025             setInterGroundDependent(it, *depIt);
1026     }
1027 }
1028 
1029 void Component::setAllPinsInterIndependent()
1030 {
1031     NodeInfoMap::iterator nmEnd = m_nodeMap.end();
1032     for (NodeInfoMap::iterator it = m_nodeMap.begin(); it != nmEnd; ++it) {
1033         // PinVector pins = (static_cast<ECNode*>(it.value().node))->pins();
1034         ECNode *node = dynamic_cast<ECNode *>(it.value().node);
1035         if (!node) {
1036             qCWarning(KTL_LOG) << "skipping not-ECNode node: " << it.value().node;
1037             continue;
1038         }
1039         PinVector pins = node->pins();
1040         PinVector::iterator pinsEnd = pins.end();
1041         for (PinVector::iterator pinsIt = pins.begin(); pinsIt != pinsEnd; ++pinsIt) {
1042             if (*pinsIt)
1043                 (*pinsIt)->removeDependentPins();
1044         }
1045     }
1046 }
1047 
1048 void Component::initElements(const uint stage)
1049 {
1050     /// @todo this function is ugly and messy and needs tidying up
1051 
1052     const ElementMapList::iterator end = m_elementMapList.end();
1053 
1054     if (stage == 1) {
1055         for (ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it) {
1056             (*it).e->add_initial_dc();
1057         }
1058         return;
1059     }
1060 
1061     for (ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it) {
1062         ElementMap m = (*it);
1063 
1064         if (m.n[3]) {
1065             m.e->setCNodes(m.n[0]->eqId(), m.n[1]->eqId(), m.n[2]->eqId(), m.n[3]->eqId());
1066         } else if (m.n[2]) {
1067             m.e->setCNodes(m.n[0]->eqId(), m.n[1]->eqId(), m.n[2]->eqId());
1068         } else if (m.n[1]) {
1069             m.e->setCNodes(m.n[0]->eqId(), m.n[1]->eqId());
1070         } else if (m.n[0]) {
1071             m.e->setCNodes(m.n[0]->eqId());
1072         }
1073     }
1074 }
1075 
1076 ECNode *Component::createPin(double x, double y, int orientation, const QString &name)
1077 {
1078     return dynamic_cast<ECNode *>(createNode(x, y, orientation, name, Node::ec_pin));
1079 }
1080 
1081 // static
1082 double Component::voltageLength(double v)
1083 {
1084     double v_max = 1e+1;
1085     double v_min = 1e-1;
1086 
1087     v = std::abs(v);
1088 
1089     if (v >= v_max)
1090         return 1.0;
1091     else if (v <= v_min)
1092         return 0.0;
1093     else
1094         return std::log(v / v_min) / std::log(v_max / v_min);
1095 }
1096 
1097 // static
1098 QColor Component::voltageColor(double v)
1099 {
1100     double prop = voltageLength(v);
1101 
1102     if (v >= 0)
1103         return QColor(int(255 * prop), int(166 * prop), 0);
1104     else
1105         return QColor(0, int(136 * prop), int(255 * prop));
1106 }
1107 
1108 // BEGIN class ElementMap
1109 ElementMap::ElementMap()
1110 {
1111     e = nullptr;
1112     for (int i = 0; i < 4; ++i)
1113         n[i] = nullptr;
1114 }
1115 // END class ElementMap
1116 
1117 #include "moc_component.cpp"