/*************************************************************************** * Copyright (C) 2004-2005 by David Saxton * * david@bluehaze.org * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "canvasitemparts.h" #include "circuitdocument.h" #include "component.h" #include "src/core/ktlconfig.h" #include "ecnode.h" #include "itemdocumentdata.h" #include "node.h" #include "pin.h" #include "simulator.h" #include "bjt.h" #include "capacitance.h" #include "cccs.h" #include "ccvs.h" #include "currentsignal.h" #include "currentsource.h" #include "diode.h" #include "inductance.h" #include "logic.h" #include "opamp.h" #include "resistance.h" #include "switch.h" #include "vccs.h" #include "vcvs.h" #include "voltagepoint.h" #include "voltagesignal.h" #include "voltagesource.h" #include #include #include #include #include #include const int dipWidth = 112; const int pairSep = 32; // Degrees per radian static const double DPR = 57.29577951308232087665461840231273527024; Component::Component( ICNDocument *icnDocument, bool newItem, const TQString &id ) : CNItem( icnDocument, newItem, id ), m_angleDegrees(0), b_flipped(false) { m_pCircuitDocument = dynamic_cast(icnDocument); for ( int i=0; i<4; ++i ) { m_pPNode[i] = 0l; m_pNNode[i] = 0l; } // Get configuration options slotUpdateConfiguration(); // And finally register this :-) icnDocument->registerItem(this); } Component::~Component() { removeElements(); Simulator::self()->detachComponent(this); } void Component::removeItem( ) { if (b_deleted) return; Simulator::self()->detachComponent(this); CNItem::removeItem(); } void Component::removeElements( bool setPinsInterIndependent ) { const ElementMapList::iterator end = m_elementMapList.end(); for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) { Element * e = (*it).e; if (e) { emit elementDestroyed(e); e->componentDeleted(); } } m_elementMapList.clear(); const SwitchList::iterator swEnd = m_switchList.end(); for ( SwitchList::iterator it = m_switchList.begin(); it != swEnd; ++it ) { Switch * sw = *it; if ( !sw ) continue; emit switchDestroyed( sw ); delete sw; } m_switchList.clear(); if ( setPinsInterIndependent ) setAllPinsInterIndependent(); } void Component::removeElement( Element * element, bool setPinsInterIndependent ) { if (!element) return; emit elementDestroyed(element); element->componentDeleted(); const ElementMapList::iterator end = m_elementMapList.end(); for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ) { ElementMapList::iterator next = it; ++next; if ( (*it).e == element ) m_elementMapList.remove(it); it = next; } if ( setPinsInterIndependent ) rebuildPinInterDepedence(); } void Component::removeSwitch( Switch * sw ) { if ( !sw ) return; emit switchDestroyed( sw ); delete sw; m_switchList.remove(sw); m_pCircuitDocument->requestAssignCircuits(); } void Component::setNodalCurrents() { const ElementMapList::iterator end = m_elementMapList.end(); for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) { ElementMap m = (*it); for ( int i=0; i<4; i++ ) { if ( m.n[i] ) { m.n[i]->mergeCurrent( m.e->m_cnodeI[i] ); } } } } void Component::initPainter( TQPainter &p ) { CNItem::initPainter(p); if ( !b_flipped && (m_angleDegrees%360 == 0) ) return; p.save(); p.translate( int(x()), int(y()) ); if (b_flipped) p.scale( -1, 1 ); p.rotate(m_angleDegrees); p.translate( -int(x()), -int(y()) ); } void Component::deinitPainter( TQPainter &p ) { if ( !b_flipped && (m_angleDegrees%360 == 0) ) return; p.restore(); } void Component::setAngleDegrees( int degrees ) { updateConnectorPoints(false); m_angleDegrees = degrees; itemPointsChanged(); updateAttachedPositioning(); p_icnDocument->requestRerouteInvalidatedConnectors(); } void Component::setFlipped( bool flipped ) { updateConnectorPoints(false); b_flipped = flipped; itemPointsChanged(); updateAttachedPositioning(); p_icnDocument->requestRerouteInvalidatedConnectors(); } void Component::itemPointsChanged() { TQPointArray transformedPoints = transMatrix( m_angleDegrees, b_flipped, 0, 0, false ).map(m_itemPoints); // transformedPoints.translate( int(x()), int(y()) ); setPoints(transformedPoints); } void Component::restoreFromItemData( const ItemData &itemData ) { CNItem::restoreFromItemData(itemData); setAngleDegrees( int(itemData.angleDegrees) ); setFlipped(itemData.flipped); } ItemData Component::itemData() const { ItemData itemData = CNItem::itemData(); itemData.angleDegrees = m_angleDegrees; itemData.flipped = b_flipped; return itemData; } TQWMatrix Component::transMatrix( int angleDegrees, bool flipped, int x, int y, bool inverse ) { TQWMatrix m; m.translate( x, y ); if (inverse) { m.rotate(-angleDegrees); if (flipped) m.scale( -1, 1 ); } else { if (flipped) m.scale( -1, 1 ); m.rotate(angleDegrees); } m.translate( -x, -y ); m.setTransformationMode( TQWMatrix::Areas ); return m; } void Component::finishedCreation() { CNItem::finishedCreation(); updateAttachedPositioning(); } void Component::updateAttachedPositioning() { if (b_deleted || !m_bDoneCreation) return; //BEGIN Transform the nodes const NodeMap::iterator end = m_nodeMap.end(); for ( NodeMap::iterator it = m_nodeMap.begin(); it != end; ++it ) { if ( !it.data().node ) kdError() << k_funcinfo << "Node in nodemap is null" << endl; else { int nx = int((std::cos(m_angleDegrees/DPR) * it.data().x) - (std::sin(m_angleDegrees/DPR) * it.data().y)); int ny = int((std::sin(m_angleDegrees/DPR) * it.data().x) + (std::cos(m_angleDegrees/DPR) * it.data().y)); if (b_flipped) nx = -nx; #define round_8(x) (((x) > 0) ? int(((x)+4)/8)*8 : int(((x)-4)/8)*8) nx = round_8(nx); ny = round_8(ny); #undef round_8 int newDir = (((m_angleDegrees + it.data().orientation)%360)+360)%360; if (b_flipped) newDir = (((180-newDir)%360)+360)%360; it.data().node->move( nx+x(), ny+y() ); it.data().node->setOrientation( (Node::node_dir)newDir ); } } //END Transform the nodes //BEGIN Transform the GuiParts TQWMatrix m; if (b_flipped) m.scale( -1, 1 ); m.rotate(m_angleDegrees); m.setTransformationMode( TQWMatrix::Areas ); const TextMap::iterator textMapEnd = m_textMap.end(); for ( TextMap::iterator it = m_textMap.begin(); it != textMapEnd; ++it ) { TQRect newPos = m.mapRect( it.data()->recommendedRect() ); it.data()->move( newPos.x() + x(), newPos.y() + y() ); it.data()->setGuiPartSize( newPos.width(), newPos.height() ); it.data()->setAngleDegrees(m_angleDegrees); } const WidgetMap::iterator widgetMapEnd = m_widgetMap.end(); for ( WidgetMap::iterator it = m_widgetMap.begin(); it != widgetMapEnd; ++it ) { TQRect newPos = m.mapRect( it.data()->recommendedRect() ); it.data()->move( newPos.x() + x(), newPos.y() + y() ); it.data()->setGuiPartSize( newPos.width(), newPos.height() ); it.data()->setAngleDegrees(m_angleDegrees); } //END Transform the GuiParts } void Component::drawPortShape( TQPainter & p ) { int h = height(); int w = width() - 1; int _x = int( x() + offsetX() ); int _y = int( y() + offsetY() ); double roundSize = 8; double slantIndent = 8; const double pi = 3.1415926536; const double DPR = 180./pi; double inner = std::atan(h/slantIndent); // Angle for slight corner double outer = pi-inner; // Angle for sharp corner int inner16 = int(16*inner*DPR); int outer16 = int(16*outer*DPR); p.save(); p.setPen( TQt::NoPen ); p.drawPolygon( areaPoints() ); p.restore(); initPainter( p ); // Left line p.drawLine( int(_x), int(_y+roundSize/2), int(_x), int(_y+h-roundSize/2) ); // Right line p.drawLine( int(_x+w), int(_y-slantIndent+h-roundSize/2), int(_x+w), int(_y+slantIndent+roundSize/2) ); // Bottom line p.drawLine( 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)) ); // Top line 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)) ); // Top left p.drawArc( int(_x), int(_y), int(roundSize), int(roundSize), 90*16, outer16 ); // Bottom left p.drawArc( int(_x), int(_y+h-roundSize), int(roundSize), int(roundSize), 180*16, outer16 ); // Top right p.drawArc( int(_x+w-roundSize), int(_y+slantIndent), int(roundSize), int(roundSize), 0, inner16 ); // Bottom right p.drawArc( int(_x+w-roundSize), int(_y-slantIndent+h-roundSize), int(roundSize), int(roundSize), 270*16, inner16 ); deinitPainter( p ); } void Component::initDIP( const TQStringList & pins ) { const int numPins = pins.size(); const int numSide = numPins/2 + numPins%2; // Pins along left for ( int i=0; i( p_icnDocument->nodeWithID( nodeId(ecNodeId) ) ); } void Component::slotUpdateConfiguration() { const LogicConfig logicConfig = LogicIn::getConfig(); const ElementMapList::iterator end = m_elementMapList.end(); for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) { if ( LogicIn * logicIn = dynamic_cast((*it).e) ) logicIn->setLogic(logicConfig); } } BJT * Component::createBJT( ECNode *c, ECNode *b, ECNode *e, bool isNPN ) { return createBJT( c->pin(), b->pin(), e->pin(), isNPN ); } Capacitance * Component::createCapacitance( ECNode *n0, ECNode *n1, double capacitance ) { return createCapacitance( n0->pin(), n1->pin(), capacitance ); } CCCS * Component::createCCCS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ) { return createCCCS( n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain ); } CCVS * Component::createCCVS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ) { return createCCVS( n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain ); } CurrentSignal * Component::createCurrentSignal( ECNode *n0, ECNode *n1, double current ) { return createCurrentSignal( n0->pin(), n1->pin(), current ); } CurrentSource * Component::createCurrentSource( ECNode *n0, ECNode *n1, double current ) { return createCurrentSource( n0->pin(), n1->pin(), current ); } Diode * Component::createDiode( ECNode *n0, ECNode *n1 ) { return createDiode( n0->pin(), n1->pin() ); } Inductance * Component::createInductance( ECNode *n0, ECNode *n1, double inductance ) { return createInductance( n0->pin(), n1->pin(), inductance ); } LogicIn * Component::createLogicIn( ECNode *node ) { return createLogicIn( node->pin() ); } LogicOut * Component::createLogicOut( ECNode *node, bool isHigh ) { return createLogicOut( node->pin(), isHigh ); } OpAmp * Component::createOpAmp( ECNode * nonInverting, ECNode * out, ECNode * inverting ) { return createOpAmp( nonInverting->pin(), out->pin(), inverting->pin() ); } Resistance * Component::createResistance( ECNode *n0, ECNode *n1, double resistance ) { return createResistance( n0->pin(), n1->pin(), resistance ); } Switch * Component::createSwitch( ECNode *n0, ECNode *n1, bool open ) { return createSwitch( n0->pin(), n1->pin(), open ); } VCCS * Component::createVCCS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ) { return createVCCS( n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain ); } VCVS * Component::createVCVS( ECNode *n0, ECNode *n1, ECNode *n2, ECNode *n3, double gain ) { return createVCVS( n0->pin(), n1->pin(), n2->pin(), n3->pin(), gain ); } VoltagePoint * Component::createVoltagePoint( ECNode *n0, double voltage ) { return createVoltagePoint( n0->pin(), voltage ); } VoltageSignal * Component::createVoltageSignal( ECNode *n0, ECNode *n1, double voltage ) { return createVoltageSignal( n0->pin(), n1->pin(), voltage ); } VoltageSource * Component::createVoltageSource( ECNode *n0, ECNode *n1, double voltage ) { return createVoltageSource( n0->pin(), n1->pin(), voltage ); } BJT* Component::createBJT( Pin *cN, Pin *bN, Pin *eN, bool isNPN ) { BJT *e = new BJT(isNPN); TQValueList pins; pins << bN << cN << eN; ElementMapList::iterator it = handleElement( e, pins ); setInterDependent( it, pins ); return e; } Capacitance* Component::createCapacitance( Pin *n0, Pin *n1, double capacitance ) { Capacitance *e = new Capacitance( capacitance, 1./LINEAR_UPDATE_RATE ); TQValueList pins; pins << n0 << n1; ElementMapList::iterator it = handleElement( e, pins ); setInterDependent( it, pins ); return e; } CCCS* Component::createCCCS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ) { CCCS *e = new CCCS(gain); TQValueList pins; pins << n0 << n1 << n2 << n3; ElementMapList::iterator it = handleElement( e, pins ); setInterDependent( it, pins ); return e; } CCVS* Component::createCCVS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ) { CCVS *e = new CCVS(gain); TQValueList pins; pins << n0 << n1 << n2 << n3; ElementMapList::iterator it = handleElement( e, pins ); setInterCircuitDependent( it, pins ); pins.clear(); pins << n0 << n1; setInterGroundDependent( it, pins ); pins.clear(); pins << n2 << n3; setInterGroundDependent( it, pins ); return e; } CurrentSignal* Component::createCurrentSignal( Pin *n0, Pin *n1, double current ) { CurrentSignal *e = new CurrentSignal( 1./LINEAR_UPDATE_RATE, current ); TQValueList pins; pins << n0 << n1; ElementMapList::iterator it = handleElement( e, pins ); setInterDependent( it, pins ); return e; } CurrentSource* Component::createCurrentSource( Pin *n0, Pin *n1, double current ) { CurrentSource *e = new CurrentSource(current); TQValueList pins; pins << n0 << n1; ElementMapList::iterator it = handleElement( e, pins ); setInterDependent( it, pins ); return e; } Diode* Component::createDiode( Pin *n0, Pin *n1 ) { Diode *e = new Diode(); TQValueList pins; pins << n0 << n1; ElementMapList::iterator it = handleElement( e, pins ); setInterDependent( it, pins ); return e; } Inductance* Component::createInductance( Pin *n0, Pin *n1, double inductance ) { Inductance *e = new Inductance( inductance, 1./LINEAR_UPDATE_RATE ); TQValueList pins; pins << n0 << n1; ElementMapList::iterator it = handleElement( e, pins ); setInterDependent( it, pins ); return e; } LogicIn *Component::createLogicIn( Pin *node ) { LogicIn *e = new LogicIn(LogicIn::getConfig()); TQValueList pins; pins << node; ElementMapList::iterator it = handleElement( e, pins ); return e; } LogicOut *Component::createLogicOut( Pin *node, bool isHigh ) { LogicOut *e = new LogicOut( LogicIn::getConfig(), isHigh); TQValueList pins; pins << node; ElementMapList::iterator it = handleElement( e, pins ); setInterDependent( it, pins ); return e; } OpAmp * Component::createOpAmp( Pin * nonInverting, Pin * inverting, Pin * out ) { OpAmp * e = new OpAmp(); TQValueList pins; pins << nonInverting << inverting << out; ElementMapList::iterator it = handleElement( e, pins ); setInterDependent( it, pins ); return e; } Resistance* Component::createResistance( Pin *n0, Pin *n1, double resistance ) { Resistance *e = new Resistance(resistance); TQValueList pins; pins << n0 << n1; ElementMapList::iterator it = handleElement( e, pins ); setInterDependent( it, pins ); return e; } Switch* Component::createSwitch( Pin *n0, Pin *n1, bool open ) { // Note that a Switch is not really an element (although in many cases it // behaves very much like one). Switch * e = new Switch( this, n0, n1, open ? Switch::Open : Switch::Closed ); m_switchList.append(e); n0->addSwitch( e ); n1->addSwitch( e ); emit switchCreated( e ); return e; } VCCS* Component::createVCCS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ) { VCCS *e = new VCCS(gain); TQValueList pins; pins << n0 << n1 << n2 << n3; ElementMapList::iterator it = handleElement( e, pins ); setInterDependent( it, pins ); return e; } VCVS* Component::createVCVS( Pin *n0, Pin *n1, Pin *n2, Pin *n3, double gain ) { VCVS *e = new VCVS(gain); TQValueList pins; pins << n0 << n1 << n2 << n3; ElementMapList::iterator it = handleElement( e, pins ); setInterCircuitDependent( it, pins ); pins.clear(); pins << n0 << n1; setInterGroundDependent( it, pins ); pins.clear(); pins << n2 << n3; setInterGroundDependent( it, pins ); return e; } VoltagePoint* Component::createVoltagePoint( Pin *n0, double voltage ) { VoltagePoint *e = new VoltagePoint(voltage); TQValueList pins; pins << n0; ElementMapList::iterator it = handleElement( e, pins ); setInterDependent( it, pins ); return e; } VoltageSignal* Component::createVoltageSignal( Pin *n0, Pin *n1, double voltage ) { VoltageSignal *e = new VoltageSignal( 1./LINEAR_UPDATE_RATE, voltage ); TQValueList pins; pins << n0 << n1; ElementMapList::iterator it = handleElement( e, pins ); setInterDependent( it, pins ); return e; } VoltageSource* Component::createVoltageSource( Pin *n0, Pin *n1, double voltage ) { VoltageSource *e = new VoltageSource(voltage); TQValueList pins; pins << n0 << n1; ElementMapList::iterator it = handleElement( e, pins ); setInterDependent( it, pins ); return e; } ElementMapList::iterator Component::handleElement( Element *e, const TQValueList & pins ) { if (!e) return m_elementMapList.end(); ElementMap em; em.e = e; int at = 0; TQValueList::ConstIterator end = pins.end(); for ( TQValueList::ConstIterator it = pins.begin(); it != end; ++it ) { (*it)->addElement(e); em.n[at++] = *it; } ElementMapList::iterator it = m_elementMapList.append(em); emit elementCreated(e); return it; } void Component::setInterDependent( ElementMapList::iterator it, const TQValueList & pins ) { setInterCircuitDependent( it, pins ); setInterGroundDependent( it, pins ); } void Component::setInterCircuitDependent( ElementMapList::iterator it, const TQValueList & pins ) { TQValueList::ConstIterator end = pins.end(); for ( TQValueList::ConstIterator it1 = pins.begin(); it1 != end; ++it1 ) { for ( TQValueList::ConstIterator it2 = pins.begin(); it2 != end; ++it2 ) { (*it1)->addCircuitDependentPin( *it2 ); } } (*it).interCircuitDependent.append( pins ); } void Component::setInterGroundDependent( ElementMapList::iterator it, const TQValueList & pins ) { TQValueList::ConstIterator end = pins.end(); for ( TQValueList::ConstIterator it1 = pins.begin(); it1 != end; ++it1 ) { for ( TQValueList::ConstIterator it2 = pins.begin(); it2 != end; ++it2 ) { (*it1)->addGroundDependentPin( *it2 ); } } (*it).interGroundDependent.append( pins ); } void Component::rebuildPinInterDepedence() { setAllPinsInterIndependent(); // Rebuild dependencies ElementMapList::iterator emlEnd = m_elementMapList.end(); for ( ElementMapList::iterator it = m_elementMapList.begin(); it != emlEnd; ++it ) { // Many copies of the pin lists as these will be affected when we call setInter*Dependent PinListList list = (*it).interCircuitDependent; PinListList::iterator depEnd = list.end(); for ( PinListList::iterator depIt = list.begin(); depIt != depEnd; ++depIt ) setInterCircuitDependent( it, *depIt ); list = (*it).interGroundDependent; depEnd = list.end(); for ( PinListList::iterator depIt = list.begin(); depIt != depEnd; ++depIt ) setInterGroundDependent( it, *depIt ); } } void Component::setAllPinsInterIndependent() { NodeMap::iterator nmEnd = m_nodeMap.end(); for ( NodeMap::iterator it = m_nodeMap.begin(); it != nmEnd; ++it ) { PinVector pins = (static_cast(it.data().node))->pins(); PinVector::iterator pinsEnd = pins.end(); for ( PinVector::iterator pinsIt = pins.begin(); pinsIt != pinsEnd; ++pinsIt ) { if ( *pinsIt ) (*pinsIt)->removeDependentPins(); } } } void Component::initElements( const uint stage ) { /// @todo this function is ugly and messy and needs tidying up const ElementMapList::iterator end = m_elementMapList.end(); if ( stage == 1 ) { for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) { (*it).e->add_initial_dc(); } return; } for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) { ElementMap m = (*it); if ( m.n[3] ) { m.e->setCNodes( m.n[0]->eqId(), m.n[1]->eqId(), m.n[2]->eqId(), m.n[3]->eqId() ); } else if ( m.n[2] ) { m.e->setCNodes( m.n[0]->eqId(), m.n[1]->eqId(), m.n[2]->eqId() ); } else if ( m.n[1] ) { m.e->setCNodes( m.n[0]->eqId(), m.n[1]->eqId() ); } else if ( m.n[0] ) { m.e->setCNodes( m.n[0]->eqId() ); } } for ( ElementMapList::iterator it = m_elementMapList.begin(); it != end; ++it ) { (*it).e->add_map(); } } ECNode * Component::createPin( double x, double y, int orientation, const TQString & name ) { return dynamic_cast( createNode( x, y, orientation, name, Node::ec_pin ) ); } //BEGIN class ElementMap ElementMap::ElementMap() { e = 0; for ( int i = 0; i < 4; ++i ) n[i] = 0; } //END class ElementMap #include "component.moc"