00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "rotoswitch.h"
00012
00013 #include "canvasitemparts.h"
00014 #include "ecnode.h"
00015 #include "libraryitem.h"
00016 #include "switch.h"
00017
00018 #include <klocale.h>
00019 #include <qpainter.h>
00020 #include <cmath>
00021 #include <cassert>
00022
00023 #include <kdebug.h>
00024
00025
00026 Item* ECRotoSwitch::construct( ItemDocument *itemDocument, bool newItem, const char *id )
00027 {
00028 return new ECRotoSwitch( (ICNDocument*)itemDocument, newItem, id );
00029 }
00030
00031 LibraryItem* ECRotoSwitch::libraryItem()
00032 {
00033 return new LibraryItem(
00034 QString("ec/roto_switch"),
00035 i18n("Rotary"),
00036 i18n("Switches"),
00037 "rotary.png",
00038 LibraryItem::lit_component,
00039 ECRotoSwitch::construct );
00040 }
00041
00042
00043 ECRotoSwitch::ECRotoSwitch( ICNDocument *icnDocument, bool newItem, const char *id )
00044 : Component( icnDocument, newItem, id ? id : "roto_switch" ),
00045 m_numPositions(0)
00046 {
00047
00048 m_name = i18n("Rotary Switch");
00049 m_desc = i18n("A single-throw N-position switch");
00050 QPointArray pa;
00051 pa.makeArc( -_pinInnerRadius, -_pinInnerRadius, 2*_pinInnerRadius, 2*_pinInnerRadius , 0, 16*360 );
00052 setItemPoints( pa );
00053
00054
00055
00056 int buttonRadius = 10;
00057 addButton( "go_left", QRect( -_pinOuterRadius/3-buttonRadius, _pinOuterRadius-3*buttonRadius, 2*buttonRadius, 2*buttonRadius ), "<", false );
00058 addButton( "go_right", QRect(_pinOuterRadius/3-buttonRadius, _pinOuterRadius-3*buttonRadius, 2*buttonRadius, 2*buttonRadius ), ">", false );
00059
00060
00061
00062
00063
00064
00065
00066 Variant * v = createProperty( "num_positions", Variant::Type::Int );
00067 v->setCaption( i18n("Number of Positions") );
00068 v->setAdvanced(false);
00069 v->setValue(6);
00070 v->setMinValue(3);
00071 m_inNode = createPin(0,height()/2,270,"in");
00072
00073 v = createProperty( "bounce", Variant::Type::Bool );
00074 v->setCaption("Bounce");
00075 v->setAdvanced(true);
00076 v->setValue(false);
00077
00078 v = createProperty( "bounce_period", Variant::Type::Double );
00079 v->setCaption("Bounce Period");
00080 v->setAdvanced(true);
00081 v->setUnit("s");
00082 v->setValue(5e-3);
00083
00084 v = createProperty( "cur_position", Variant::Type::Int );
00085 v->setHidden( true );
00086 v->setValue( 0 );
00087
00088
00089
00090
00091 }
00092
00093
00094 ECRotoSwitch::~ECRotoSwitch()
00095 {
00096 }
00097
00098
00099 void ECRotoSwitch::dataChanged()
00100 {
00101 bool bounce = dataBool("bounce");
00102 int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3);
00103 m_curPosition = dataInt( "cur_position" );
00104 setUpSwitches();
00105 if(m_positions[m_curPosition].posSwitch->state() != Switch::Closed)
00106 {
00107 m_positions[m_curPosition].posSwitch->setState(Switch::Closed);
00108 }
00109 for(int i = 0; i < m_numPositions; i++)
00110 {
00111 m_positions[i].posSwitch->setBounce( bounce, bouncePeriod_ms );
00112 }
00113 }
00114
00115 inline int roundTo10(int a){return ((a/10)+(a%10<5?0:1))*10;}
00116 void ECRotoSwitch::drawShape( QPainter &p )
00117 {
00118 initPainter(p);
00119
00120 int cx = static_cast<int>(x());
00121 int cy = static_cast<int>(y());
00122
00123 const int rotorRadius = 5;
00124
00125
00126 p.drawEllipse(cx - rotorRadius, cy-rotorRadius, 2*rotorRadius, 2*rotorRadius);
00127
00128 p.drawLine(cx, cy+rotorRadius, cx, cy+_pinInnerRadius);
00129
00130
00131 double angleBetweenPositions = (4*M_PI/3)/(m_numPositions - 1);
00132
00133
00135 #define round_8(a) (((a) > 0) ? int(((a)+4)/8)*8 : int(((a)-4)/8)*8)
00136 for(int i = 0; i < m_numPositions ; i++)
00137 {
00138 double angle = (7*M_PI/6) - (i * angleBetweenPositions);
00139 int contactX = static_cast<int>(_contactRingRadius * cos(angle));
00140 int contactY = static_cast<int>(_contactRingRadius * sin(angle));
00141
00142 p.drawEllipse(cx+contactX-_contactRadius, cy-contactY-_contactRadius, 2*_contactRadius, 2*_contactRadius);
00143 int pinX, pinY;
00144 switch(m_positions[i].pinAngle)
00145 {
00146 case 180:
00147 pinX = _pinInnerRadius;
00148 pinY = round_8(contactY);
00149 break;
00150 case 90:
00151 pinX = round_8(contactX);
00152 pinY = _pinInnerRadius;
00153 break;
00154 case 0:
00155 pinX = -_pinInnerRadius;
00156 pinY = round_8(contactY);
00157 break;
00158 default:
00159 assert(!"Bad pin angle");
00160 }
00161 p.drawLine(cx+contactX, cy-contactY, cx+pinX, cy-pinY);
00162
00163 }
00164 #undef round_8
00165
00166 double angle = (7*M_PI/6) - (m_curPosition * angleBetweenPositions);
00167 int contactX = static_cast<int>(_contactRingRadius * cos(angle));
00168 int contactY = static_cast<int>(_contactRingRadius * sin(angle));
00169 int rotorX = static_cast<int>(rotorRadius * cos(angle));
00170 int rotorY = static_cast<int>(rotorRadius * sin(angle));
00171 p.drawLine(cx+rotorX, cy-rotorY, cx+contactX, cy-contactY);
00172
00173 deinitPainter(p);
00174 }
00175
00176 void ECRotoSwitch::buttonStateChanged( const QString & id, bool state )
00177 {
00178 SwitchPosition& curSP = m_positions[m_curPosition];
00179 int nextPos = m_curPosition;
00180 if(m_numPositions < 2)
00181 {
00182 return;
00183 }
00184 if(!state)
00185 {
00186 if(!curSP.isMomentary)
00187 {
00188 return;
00189 }
00190
00191 if(m_curPosition == 0)
00192 {
00193 nextPos = m_curPosition + 1;
00194 }
00195 else if(m_curPosition == m_numPositions - 1)
00196 {
00197 nextPos = m_curPosition - 1;
00198 }
00199
00200 }
00201 else
00202 {
00203 if(id == "go_left" && m_curPosition > 0)
00204 {
00205 nextPos = m_curPosition - 1;
00206 }
00207 else if(id == "go_right" && m_curPosition < m_numPositions - 1)
00208 {
00209 nextPos = m_curPosition + 1;
00210 }
00211
00212 }
00213 if(nextPos != m_curPosition)
00214 {
00215 SwitchPosition& nextSP = m_positions[nextPos];
00216
00217 curSP.posSwitch->setState(Switch::Open);
00218 nextSP.posSwitch->setState(Switch::Closed);
00219
00220 m_curPosition = nextPos;
00221
00222 property( "cur_position" )->setValue( m_curPosition );
00223 }
00224 }
00225
00226
00232 void ECRotoSwitch::setUpSwitches()
00233 {
00234 if( dataInt("num_positions") == m_numPositions )
00235 {
00236
00237 return;
00238 }
00239
00240 for(int i=0; i<m_numPositions; i++)
00241 {
00242 SwitchPosition& sp = m_positions[i];
00243 QString pinName = QString("pin_%1").arg(i);
00244 removeNode(pinName);
00245 removeSwitch(sp.posSwitch);
00246 }
00247
00248 m_numPositions = dataInt("num_positions");
00249 if(m_curPosition >= m_numPositions )
00250 {
00251 setActivePosition( m_numPositions - 1 );
00252 }
00253 m_positions.clear();
00254 m_positions.reserve(m_numPositions);
00255 double angleBetweenPositions = (4*M_PI/3)/(m_numPositions - 1);
00256
00257 for( int i = 0; i < m_numPositions; i++)
00258 {
00259 double angle = (7*M_PI/6) - (i * angleBetweenPositions);
00260 int contactX = static_cast<int>(_contactRingRadius * cos(angle));
00261 int contactY = static_cast<int>(_contactRingRadius * sin(angle));
00262
00263 SwitchPosition sp;
00264 if(angle > 3*M_PI/4)
00265 {
00266 sp.pinAngle = 0;
00267 contactX = -_pinOuterRadius;
00268 }
00269 else if(angle > M_PI/4)
00270 {
00271 sp.pinAngle = 90;
00272 contactY=_pinOuterRadius;
00273 }
00274 else
00275 {
00276 sp.pinAngle = 180;
00277 contactX = _pinOuterRadius;
00278 }
00279
00280
00281
00282 sp.node = createPin(contactX,-contactY,sp.pinAngle,QString("pin_%1").arg(i));
00283 sp.posSwitch = createSwitch(m_inNode, sp.node, true);
00284 sp.isMomentary = false;
00285 m_positions.push_back(sp);
00286 }
00287 updateAttachedPositioning();
00288
00289
00290 setChanged();
00291 }
00292
00299 void ECRotoSwitch::setActivePosition(int newPosition)
00300 {
00301 SwitchPosition& curSP = m_positions[m_curPosition];
00302 SwitchPosition& nextSP = m_positions[newPosition];
00303
00304 curSP.posSwitch->setState(Switch::Open);
00305 nextSP.posSwitch->setState(Switch::Closed);
00306
00307 m_curPosition = newPosition;
00308
00309 property( "cur_position" )->setValue( m_curPosition );
00310
00311 }
00312