2 Qanava - Graph drawing library for QT
3 Copyright (C) 2006 Benoit AUTHEMAN
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 //-----------------------------------------------------------------------------
21 // This file is a part of the Qanava software.
23 // \file qanLayout.cpp
24 // \author Benoit Autheman (benoit@libqanava.org)
26 //-----------------------------------------------------------------------------
30 #include "./qanLayout.h"
31 #include "./qanSimpleLayout.h"
38 namespace qan
{ // ::qan
41 /* Layout Generation Management *///-------------------------------------------
42 void Layout::resetNodesPositions( Graph
& graph
)
44 Node::List
& nodes
= graph
.getNodes( );
45 for ( Node::List::iterator nodeIter
= nodes
.begin( ); nodeIter
!= nodes
.end( ); nodeIter
++ )
46 ( *nodeIter
)->setPosition( -1.0f
, -1.0f
);
48 //-----------------------------------------------------------------------------
52 /* Random Layout Generation Management *///------------------------------------
53 void Random::layout( Graph
& graph
, QGraphicsScene
* scene
, QRectF r
, QProgressDialog
* progress
, int step
)
57 progress
->setMaximum( graph
.getNodeCount( ) );
58 progress
->setValue( 0 );
61 srand( QDateTime::currentDateTime( ).toTime_t( ) );
63 Node::List
& nodes
= graph
.getNodes( );
64 for ( Node::List::iterator nodeIter
= nodes
.begin( ); nodeIter
!= nodes
.end( ); nodeIter
++ )
66 Node
* node
= *nodeIter
;
68 float w
= ( float )( ( rand( ) % 100 ) / 100.0 * r
.width( ) );
69 float h
= ( float )( ( rand( ) % 100 ) / 100.0 * r
.height( ) );
70 node
->setPosition( w
, h
);
73 progress
->setValue( progress
->value( ) + 1 );
79 //-----------------------------------------------------------------------------
82 /* Force Layout Generation Management *///-------------------------------------
83 /*! Initial positions will be generated using a fixed layout (random or colimacon) if step is
86 void UndirectedGraph::layout( Graph
& graph
, QGraphicsScene
* scene
, QRectF r
, QProgressDialog
* progress
, int step
)
93 progress
->setMaximum( runCount
);
94 progress
->setValue( 0 );
97 // Generate a random layout for algorithm initialisation
100 //Random initalLayout;
101 Colimacon initalLayout
;
102 initalLayout
.layout( graph
, scene
, r
);
105 // Apply the spring force algorithm
106 std::vector
< VectorF
> positions
;
107 positions
.reserve( graph
.getNodeCount( ) + 1 ); // Last position reserved for a virtual center node
109 for ( ; n
< graph
.getNodeCount( ) + 1; n
++ )
110 positions
.push_back( VectorF( 2 ) );
111 Node::Set nodesSet
; graph
.collectNodes( nodesSet
);
113 _center
.setPosition( r
.width( ) / 2, r
.height( ) / 2 );
114 //_center.setPosition( 100., 100. );
115 Node::List
& nodes
= graph
.getNodes( );
116 for ( int iter
= 0; iter
< runCount
; iter
++ )
118 double modification
= 0.;
120 // Compute new nodes positions using the spring embedder model
121 Node::List::iterator nodeIter
= nodes
.begin( );
122 for ( n
= 0; nodeIter
!= nodes
.end( ); n
++, nodeIter
++ )
124 Node
& node
= **nodeIter
;
126 Node::Set adjacentNodes
;
127 node
.getAdjacentNodesSet( adjacentNodes
);
128 if ( graph
.isRootNode( node
) )
129 adjacentNodes
.insert( &_center
);
130 VectorF fspring
= computeSpringForce( node
, adjacentNodes
, graph
);
131 VectorF frep
= computeRepulseForce( node
, adjacentNodes
, nodesSet
, graph
);
134 delta
= ( frep
+ fspring
) / ( float )( nodes
.size( ) + 1.f
);
135 positions
[ n
] = node
.getPosition( ) + delta
;
136 modification
+= length2( delta
);
139 // Apply modifications for a virtual center node connected to all root nodes
142 VectorF fspring
= computeSpringForce( _center
, graph
.getRootNodesSet( ), graph
);
143 VectorF frep
= computeRepulseForce( _center
, graph
.getRootNodesSet( ), nodesSet
, graph
);
146 delta
= ( frep
+ fspring
) / ( float )( nodes
.size( ) + 1.f
);
147 positions
[ n
] = _center
.getPosition( ) + delta
;
150 // Move the nodes to their new positions
152 for ( nodeIter
= nodes
.begin( ); nodeIter
!= nodes
.end( ); nodeIter
++, p
++ )
153 ( *nodeIter
)->setPosition( positions
[ p
] );
154 _center
.setPosition( positions
[ nodes
.size( ) ] );
156 // Stop iterating if node have converged to a fixed position
157 if ( modification
< ( 5. * nodes
.size( ) ) )
160 // Update progress bar
162 progress
->setValue( iter
);
164 // Detect process interruption
165 if ( progress
!= 0 && progress
->wasCanceled( ) )
173 VectorF
UndirectedGraph::computeRepulseForce( Node
& u
, Node::Set
& adjacentNodes
, Node::Set
& nodes
, Graph
& graph
)
176 force( 0 ) = force( 1 ) = 0.f
;
178 // Compute repulsion forces for all non adjacent nodes
179 Node::Set
nonAdjacentNodes( nodes
);
180 nonAdjacentNodes
.subtract( adjacentNodes
);
181 if ( !graph
.isRootNode( u
) )
182 nonAdjacentNodes
.insert( &_center
);
184 Node::Set::iterator nonAdjacentNodeIter
= nonAdjacentNodes
.begin( );
185 for ( ; nonAdjacentNodeIter
!= nonAdjacentNodes
.end( ); nonAdjacentNodeIter
++ )
187 Node
& v
= **nonAdjacentNodeIter
;
191 // Compute repulsion forces between item and
192 VectorF
& pu
= u
.getPosition( );
193 VectorF
& pv
= v
.getPosition( );
194 VectorF uv
= pv
- pu
;
195 uv
*= - ( 80 * 80 ) / ( 1.0 + length2( uv
) );
201 VectorF
UndirectedGraph::computeSpringForce( Node
& u
, Node::Set
& adjacentNodes
, Graph
& graph
)
204 force( 0 ) = 0.f
; force( 1 ) = 0.f
;
206 // Compute attraction forces for all adjacent nodes (roots nodes are considered adjacents)
207 Node::Set::iterator adjacentNodeIter
= adjacentNodes
.begin( );
208 for ( ; adjacentNodeIter
!= adjacentNodes
.end( ); adjacentNodeIter
++ )
210 Node
& v
= **adjacentNodeIter
;
212 // Compute attraction forces between item and
213 VectorF
& pu
= u
.getPosition( );
214 VectorF
& pv
= v
.getPosition( );
215 VectorF uv
= pv
- pu
;
217 double l
= length( uv
) / 100.f
;
220 size
= 2.f
* log( l
);
229 float UndirectedGraph::length( const VectorF
& v
)
231 return sqrt( ( v( 0 ) * v( 0 ) ) + ( v( 1 ) * v( 1 ) ) );
234 float UndirectedGraph::length2( const VectorF
& v
)
236 return ( v( 0 ) * v( 0 ) ) + ( v( 1 ) * v( 1 ) );
238 //-----------------------------------------------------------------------------