00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "OrientedEdgeItem.h"
00022
00023 #include "NodeItem.h"
00024 #include "GraphScene.h"
00025 #include "node.h"
00026 #include "edge.h"
00027 #include "graph.h"
00028 #include "math_constants.h"
00029
00030 #include <QGraphicsScene>
00031 #include <QGraphicsSceneMouseEvent>
00032 #include <QPainter>
00033 #include <QPen>
00034 #include <QPainterPath>
00035 #include <QLine>
00036 #include <QPolygonF>
00037 #include <QtAlgorithms>
00038 #include <KDebug>
00039 #include <math.h>
00040 #include <QGraphicsSimpleTextItem>
00041
00042 OrientedEdgeItem::OrientedEdgeItem( Edge* edge, QGraphicsItem* parent )
00043 : QObject( 0 ), QGraphicsPathItem( parent )
00044 {
00045 _edge = edge;
00046 _loop = ( _edge->from() == edge->to() );
00047 _index = _edge->relativeIndex();
00048 _name = new QGraphicsSimpleTextItem( this );
00049 _value = new QGraphicsSimpleTextItem( this );
00050 setZValue( - _index );
00051 setFlag( ItemIsSelectable, true );
00052 connectSignals();
00053 updateAttributes();
00054 setPath( createCurves() );
00055 }
00056
00057 OrientedEdgeItem::~OrientedEdgeItem()
00058 {
00059
00060
00061 }
00062
00063 void OrientedEdgeItem::connectSignals()
00064 {
00065 connect( _edge, SIGNAL( changed() ), this, SLOT( updatePos() ) );
00066 connect( _edge, SIGNAL( removed() ), this, SLOT( remove() ) );
00067 }
00068
00069 QPolygonF OrientedEdgeItem::createArrow( const QPointF& Pos1, const QPointF& Pos2 ) const
00070 {
00071 QLineF line( Pos1, Pos2 );
00072 qreal angle = ::acos( line.dx() / line.length() );
00073 if( line.dy() >= 0 )
00074 {
00075 angle = TwoPi - angle;
00076 }
00077 qreal arrowSize = 10;
00078
00079 QPointF destArrowP1 = Pos2 + QPointF( sin( angle - PI_3 ) * arrowSize, cos( angle - PI_3 ) * arrowSize );
00080 QPointF destArrowP2 = Pos2 + QPointF( sin( angle - Pi + PI_3 ) * arrowSize, cos( angle - Pi + PI_3 ) * arrowSize );
00081 QPolygonF arrow( QPolygonF() << destArrowP1 << Pos2 << destArrowP2 );
00082
00084 qreal x = Pos2.x() - Pos1.x();
00085 qreal y = Pos2.y() - Pos1.y();
00086
00087 x -= x / 2;
00088 y -= y / 2;
00089 arrow.translate( -x, -y );
00090 return arrow;
00091 }
00092
00093 QPainterPath OrientedEdgeItem::createLoop( QPointF pos ) const
00094 {
00095 QPainterPath p;
00096 Graph* g = qobject_cast<Graph*>( _edge->parent() );
00097 qreal size = 30 + ( 20 * _index );
00098 qreal angle = atan2(( pos.x() - g->relativeCenter().x() ), ( pos.y() - g->relativeCenter().y() ) );
00099 qreal posx = ( pos.x() - ((( size / 2 ) * sin( angle ) ) * -1 ) - ( size / 2 ) );
00100 qreal posy = ( pos.y() + ((( size / 2 ) * cos( angle ) ) ) - ( size / 2 ) );
00101 p.addEllipse( posx, posy, size, size );
00102 return p;
00103 }
00104
00105 QPainterPath OrientedEdgeItem::createCurves() const
00106 {
00107 QPointF Pos1 = _edge->connectorFrom()->parentItem()->mapToScene( _edge->connectorFrom()->x() + ( _edge->connectorFrom()->boundingRect().width() / 2 ), _edge->connectorFrom()->y() + ( _edge->connectorFrom()->boundingRect().height() / 2 ) );
00108
00109 if( _loop ) return createLoop( Pos1 );
00110
00111 QPointF Pos2 = _edge->connectorTo()->parentItem()->mapToScene( _edge->connectorTo()->x() + ( _edge->connectorTo()->boundingRect().width() / 2 ), _edge->connectorTo()->y() + ( _edge->connectorTo()->boundingRect().height() / 2 ) );
00112 QPolygonF arrow = createArrow( Pos1, Pos2 );
00113
00114 if( Pos1.x() > Pos2.x() )
00115 {
00116 qSwap( Pos1, Pos2 );
00117 }
00118
00119 if( ! _edge->graph()->directed() )
00120 {
00121 QPainterPath p;
00122 p.moveTo( Pos1 );
00123 p.lineTo( Pos2 );
00124 return p;
00125 }
00126
00127 qreal x = Pos2.x() - Pos1.x();
00128 qreal y = Pos2.y() - Pos1.y();
00129 qreal angle = atan2( y, x );
00130
00132 qreal theta = angle + PI_2;
00133 qreal finalX = cos( theta );
00134 qreal finalY = sin( theta );
00135 int index = _index;
00136
00137 if( index & 1 )
00138 {
00139 ++index;
00140 finalX *= ( -1 );
00141 finalY *= ( -1 );
00142 }
00143
00144 qreal size = sqrt( pow(( x * 0.1 ), 2 ) + pow(( y * 0.1 ), 2 ) ) * index;
00145
00146 finalX *= size;
00147 finalY *= size;
00148 finalX += Pos1.x() + x / 2;
00149 finalY += Pos1.y() + y / 2;
00150
00152 QPainterPath p;
00153 p.moveTo( Pos1 );
00154 p.quadTo( finalX, finalY, Pos2.x(), Pos2.y() );
00155
00157 QPointF middle = p.pointAtPercent( 0.5 );
00158
00159 x = Pos1.x() + ( Pos2.x() - Pos1.x() ) / 2;
00160 y = Pos1.y() + ( Pos2.y() - Pos1.y() ) / 2;
00161 QLineF line2( QPointF( x, y ) , middle );
00162 arrow.translate( +line2.dx() , +line2.dy() );
00163 p.addPolygon( arrow );
00164
00165 return p;
00166 }
00167
00168 void OrientedEdgeItem::mousePressEvent( QGraphicsSceneMouseEvent * )
00169 {
00170 }
00171
00172 void OrientedEdgeItem::mouseReleaseEvent( QGraphicsSceneMouseEvent * )
00173 {
00174 }
00175
00176 void OrientedEdgeItem::remove()
00177 {
00178 scene()->removeItem( this );
00179 deleteLater();
00180 }
00181
00182 void OrientedEdgeItem::updatePos()
00183 {
00184 GraphScene* gScene = dynamic_cast<GraphScene*>( scene() );
00185 if( gScene->hideEdges() )
00186 {
00187 gScene->updateAfter( this );
00188 }
00189 QLine q( _edge->connectorFrom()->parentItem()->mapToScene( _edge->connectorFrom()->x() + ( _edge->connectorFrom()->boundingRect().width() / 2 ), _edge->connectorFrom()->y() + ( _edge->connectorFrom()->boundingRect().height() / 2 ) ).toPoint(), _edge->connectorTo()->parentItem()->mapToScene( _edge->connectorTo()->x() + ( _edge->connectorTo()->boundingRect().width() / 2 ), _edge->connectorTo()->y() + ( _edge->connectorTo()->boundingRect().height() / 2 ) ).toPoint() );
00190 qreal size = sqrt( pow( q.dx(), 2 ) + pow( q.dy(), 2 ) );
00191 if( _edge->from() != _edge->to() && size < 20 )
00192 {
00193 setPath( QPainterPath() );
00194 }
00195 else
00196 {
00197 setPath( createCurves() );
00198 }
00199 updateAttributes();
00200 }
00201
00202 void OrientedEdgeItem::updateAttributes()
00203 {
00204 Qt::PenStyle s;
00205 if( _edge->style() == "dash" )
00206 {
00207 s = Qt::DashLine;
00208 }
00209 else if( _edge->style() == "dot" )
00210 {
00211 s = Qt::DotLine;
00212 }
00213 else if( _edge->style() == "dash dot" )
00214 {
00215 s = Qt::DashDotLine;
00216 }
00217 else if( _edge->style() == "solid" )
00218 {
00219 s = Qt::SolidLine;
00220 }
00221 else
00222 {
00223 s = Qt::SolidLine;
00224 }
00225
00226 setPen( QPen( QBrush( QColor( _edge->color() ) ), _edge->width(), s, Qt::RoundCap, Qt::RoundJoin ) );
00227 _value->hide();
00228 _name->hide();
00229 QPointF middle = path().pointAtPercent( 0.5 );
00230 _name->setText( _edge->name() );
00231 _value->setText( _edge->value() );
00232
00233 if( _edge->from() == _edge->to() )
00234 {
00235 qreal x1 = boundingRect().x() + boundingRect().width() + 5;
00236 qreal y1 = boundingRect().y() + ( boundingRect().height() / 2 ) - 10;
00237 _name->setPos( x1, y1 );
00238 _value->setPos( x1, y1 + 14 );
00239 }
00240 else
00241 {
00242 _name->setPos( middle.x() - _name->boundingRect().width() / 2, middle.y() );
00243 _value->setPos( middle.x() - _name->boundingRect().width() / 2, middle.y() - 14 );
00244 }
00245
00246 if( _edge->showValue() )
00247 {
00248 _value->show();
00249 }
00250 if( _edge->showName() )
00251 {
00252 _name->show();
00253 }
00254 update();
00255 }
00256
00257 void OrientedEdgeItem::paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget )
00258 {
00259 Q_UNUSED( option )
00260 Q_UNUSED( widget )
00261 if( isSelected() )
00262 {
00263 painter->setPen( QPen( Qt::black, _edge->width(), Qt::DotLine ) );
00264 }
00265 painter->drawPath( createCurves() );
00266 }
00267
00268 #include "OrientedEdgeItem.moc"