File indexing completed on 2024-05-05 05:46:14
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"