IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Algorithmes et structures de données Discussion :

Algorithme Fruchterman / Ressort


Sujet :

Algorithmes et structures de données

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 11
    Par défaut Algorithme Fruchterman / Ressort
    Bonjour à tous!


    Je travaille actuellement sur un programme qui permet de convertir une expression régulière en un automate déterministe. J'aimerais pouvoir représenter l'automate produit. Pour cela, j'ai besoin de positionner correctement les noeuds de mon automate (qui peut être vu comme un graphe orienté).

    J'ai vu qu'il existait l'algorithme de Fruchterman et le positionnement par ressort. J'ai essayé de l'implémenter en Java mais sans succès. Je voulais donc savoir si quelqu'un avait déjà implémenté ce genre d'algorithme et si cette personne pouvait m'aider....


    Je vous remercie!

  2. #2
    Rédacteur

    Homme Profil pro
    Comme retraité, des masses
    Inscrit en
    Avril 2007
    Messages
    2 978
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 84
    Localisation : Suisse

    Informations professionnelles :
    Activité : Comme retraité, des masses
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2007
    Messages : 2 978
    Par défaut
    Salut!
    Je travaille actuellement sur un programme qui permet de convertir une expression régulière en un automate déterministe
    Etrange formulation du problème! Wikipedia définit un automate comme un "dispositif se comportant de manière automatique, c'est-à-dire sans intervention d'un humain". Un programme informatique produit des résultats numériques, ou, cas échéant graphiques, mais jamais un dispositif.
    Jean-Marc Blanc

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 11
    Par défaut
    Un automate traitant des expressions régulières n'est jamais qu'un graphe orienté, dont les arrêtes sont étiquetés par des symboles. Il s'agit d'un automate car le graphe produit permet de déterminer si oui ou non l'expression régulière est acceptée par l'automate. (Voir JFlex). Mais là n'est pas mon problème. Mon problème principal est de disposer de manière optimale les noeuds d'un graphe dans une surface (typiquement une fenêtre dont les dimensions sont précisées).

  4. #4
    Rédacteur
    Avatar de pseudocode
    Homme Profil pro
    Architecte système
    Inscrit en
    Décembre 2006
    Messages
    10 062
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte système
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2006
    Messages : 10 062
    Par défaut
    Citation Envoyé par vince73_2 Voir le message
    Un automate traitant des expressions régulières n'est jamais qu'un graphe orienté, dont les arrêtes sont étiquetés par des symboles. Il s'agit d'un automate car le graphe produit permet de déterminer si oui ou non l'expression régulière est acceptée par l'automate. (Voir JFlex). Mais là n'est pas mon problème. Mon problème principal est de disposer de manière optimale les noeuds d'un graphe dans une surface (typiquement une fenêtre dont les dimensions sont précisées).
    Télécharge le logiciel "yEd" (java) et regarde s'il y a un type de layout qui correspond a tes attentes. Si c'est le cas, tu auras déjà un axe de recherche concernant l'algorithme qu'il te faut.



    (ce n'est pas de la pub déguisée pour ce logiciel, bien que je l'utilise souvent. C'est surtout que ce logiciel inclut des algos de layout automatique)
    ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.

  5. #5
    Membre Expert
    Avatar de Franck Dernoncourt
    Homme Profil pro
    PhD student in AI @ MIT
    Inscrit en
    Avril 2010
    Messages
    894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : PhD student in AI @ MIT
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2010
    Messages : 894
    Par défaut
    Personnellement j'utilise Graphviz : il n'est pas parfait mais peut beaucoup aider dans certaines situations.

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 11
    Par défaut
    Merci beaucoup pour votre aide, au fait je sais l'algorithme qu'il me faut : c'est Fruchterman (algorithme des ressorts), mais le problème c'est que je n'arrive pas à l'implémenter.

  7. #7
    Rédacteur
    Avatar de pseudocode
    Homme Profil pro
    Architecte système
    Inscrit en
    Décembre 2006
    Messages
    10 062
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte système
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2006
    Messages : 10 062
    Par défaut
    Citation Envoyé par vince73_2 Voir le message
    Merci beaucoup pour votre aide, au fait je sais l'algorithme qu'il me faut : c'est Fruchterman (algorithme des ressorts), mais le problème c'est que je n'arrive pas à l'implémenter.
    C'est assez simple comme algorithme. Le pseudocode est donné sur wikipedia.

    A chaque itération on déplace indépendamment chaque noeuds du graphe, en suivant une loi physique, i.e. on calcule un vecteur de déplacement en fonction de l'attraction/répulsion, la distance, la masse, ...
    ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 11
    Par défaut
    Je vais encore essayer de l'implémenter, merci pour les explications mais la physique et moi on fait 2 lol.

    L'as-tu déjà implémenté?

    Par exemple la valeur total_kinetic_energy comment tu la fixes?Les forces d'attractions et de répulsions comment se calculent-elles??


    Un grand merci!

  9. #9
    Rédacteur
    Avatar de pseudocode
    Homme Profil pro
    Architecte système
    Inscrit en
    Décembre 2006
    Messages
    10 062
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte système
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2006
    Messages : 10 062
    Par défaut
    Citation Envoyé par vince73_2 Voir le message
    Je vais encore essayer de l'implémenter, merci pour les explications mais la physique et moi on fait 2 lol.

    L'as-tu déjà implémenté?
    Oui, plusieurs fois. Même 1 fois ou 2 dans le cadre d'un problème posé sur ce forum... une histoire de fenêtres façon "exposé" du Mac, et aussi une histoire de disposition d'articles sur une page web.

    Par exemple la valeur total_kinetic_energy comment tu la fixes?Les forces d'attractions et de répulsions comment se calculent-elles??
    La valeur total_kinetic_energy on ne la fixe pas, elle est calculée a chaque itération pour savoir de "combien" on a bougé les éléments. Les forces d'attractions/répulsions sont généralement des lois physiques : coulomb, newton, ... bref des lois basées sur l'inverse de la distance, au carré.
    ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.

  10. #10
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 11
    Par défaut
    Merci pour tous explications! Est-ce que je pourrais jeter un coup d'oeil sur le code source des algorithmes que tu as déjà implémentés? J'ai encore regardé l'algorithme, mais y a beaucoup de valeurs que je ne sais pas comment fixer ou calculer.

    Par exemple : timestep, damping et choisir une valeur pour laquelle la boucle s'arrête. Aussi, est-ce que cet algorithme est applicable pour le cas d'une fenêtre dont la taille est fixée?


    Un grand merci, c'est vraiment gentil de ta part!

  11. #11
    Rédacteur
    Avatar de pseudocode
    Homme Profil pro
    Architecte système
    Inscrit en
    Décembre 2006
    Messages
    10 062
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte système
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2006
    Messages : 10 062
    Par défaut
    Citation Envoyé par vince73_2 Voir le message
    Merci pour tous explications! Est-ce que je pourrais jeter un coup d'oeil sur le code source des algorithmes que tu as déjà implémentés? J'ai encore regardé l'algorithme, mais y a beaucoup de valeurs que je ne sais pas comment fixer ou calculer.

    Par exemple : timestep, damping et choisir une valeur pour laquelle la boucle s'arrête.
    Il faudrait que je regarde dans mes sources si j'ai quelque chose d'exploitable, mais j'ai un doute. Pour les valeurs des paramètres, c'est surtout une question de tuning manuel.

    Aussi, est-ce que cet algorithme est applicable pour le cas d'une fenêtre dont la taille est fixée?!
    Implémenter seulement l'algo de Fruchterman ne va pas "démêler" ton graphe. Il vaut mieux commencer par un algo comme Kamada-Kawai.

    L'algo de Fruchterman peut ensuite être appliqué pour répartir harmonieusement le résultat.
    ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 11
    Par défaut
    Rebonjour, j'ai essayé de trouver l'algorithme de Kamada Kawai mais je ne l'ai pas trouvé.

    As-tu trouvé dans tes sources quelque chose d'utile? Je te remercie vraiment!

  13. #13
    Rédacteur
    Avatar de pseudocode
    Homme Profil pro
    Architecte système
    Inscrit en
    Décembre 2006
    Messages
    10 062
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte système
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2006
    Messages : 10 062
    Par défaut
    [quote=vince73_2;6342212]Rebonjour, j'ai essayé de trouver l'algorithme de Kamada Kawai mais je ne l'ai pas trouvé.[QUOTE]

    Pourtant il y a des références partout sur Internet. Par exemple celle-ci.

    As-tu trouvé dans tes sources quelque chose d'utile? Je te remercie vraiment!
    Je suis encore en week-end.

    Je verrai demain au boulot, mais je ne pense pas qu'un simple système a ressort suffise pour faire ce que tu veux.
    ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.

  14. #14
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut
    bonjour vince73_2
    Comme l'ont dit Xavier et Franck Dernoncourt de tres bons pseud-codes existent un peu partout entre autres wikipedia .
    L'implementation qui normalement n'est pas du ressort de ce forum est plutot delicate car l'algo de Fruchterman base sur un principe d'equilibre physique comporte 2 versions:
    -version masses pesantes (gravite de Newton) relies par ressorts(de Hooke) en action-reaction
    -version charges elecriques (Coulomb) relies par ressorts(de Hooke) en action reactions dans un volume d'espace se heurte aux difficultes habituelles des operations sur les flottants et les erreurs d'arrondi .
    Les iterations doivent etre limites pour raison de convergence numerique (sujet difficile s'il en est).
    Neamoins voici un code source complet en c# ecrit par un certain Bradley Smith qui montre les difficultes inherantes aux calculs sur les flottants et
    qui pourrait satisfaire ta curiosite.
    Le projet ecris en c# est complet et comprend meme l'affichage graphique avec un custom control diagram (l'algorithme est implemente dans ce custom control)....
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
     
    //CODE DU CUSTOM CONTROL 
    //
    // A Force-Directed Diagram Layout Algorithm
    // Bradley Smith - 2010/07/01
     
    using System;
    using System.Collections.Generic;
    using System.Drawing;
     
    /// <summary>
    /// Represents a simple diagram consisting of nodes and connections, implementing a 
    /// force-directed algorithm for automatically arranging the nodes.
    /// </summary>
    public class Diagram {
     
    	private const double ATTRACTION_CONSTANT = 0.1;		// spring constant
    	private const double REPULSION_CONSTANT = 10000;	// charge constant
     
    	private const double DEFAULT_DAMPING = 0.5;
    	private const int DEFAULT_SPRING_LENGTH = 100;
    	private const int DEFAULT_MAX_ITERATIONS = 500;
     
    	private List<Node> mNodes;
     
    	/// <summary>
    	/// Gets a read-only collection of the nodes in this Diagram.
    	/// </summary>
    	public IList<Node> Nodes {
    		get {
    			return mNodes.AsReadOnly();
    		}
    	}
     
    	/// <summary>
    	/// Initialises a new instance of the Diagram class.
    	/// </summary>
    	public Diagram() {
    		mNodes = new List<Node>();
    	}
     
    	/// <summary>
    	/// Adds the specified Node to this Diagram.
    	/// </summary>
    	/// <param name="node">The Node to add to the diagram.</param>
    	/// <returns>True if the node was added, false if the node is already on this Diagram.</returns>
    	public bool AddNode(Node node) {
    		if (node == null) throw new ArgumentNullException("node");
     
    		if (!mNodes.Contains(node)) {
    			// add node, associate with diagram, then add all connected nodes
    			mNodes.Add(node);
    			node.Diagram = this;
    			foreach (Node child in node.Connections) AddNode(child);
    			return true;
    		}
    		else {
    			return false;
    		}
    	}
     
    	/// <summary>
    	/// Runs the force-directed layout algorithm on this Diagram, using the default parameters.
    	/// </summary>
    	public void Arrange() {
    		Arrange(DEFAULT_DAMPING, DEFAULT_SPRING_LENGTH, DEFAULT_MAX_ITERATIONS, true);
    	}
     
    	/// <summary>
    	/// Runs the force-directed layout algorithm on this Diagram, offering the option of a random or deterministic layout.
    	/// </summary>
    	/// <param name="deterministic">Whether to use a random or deterministic layout.</param>
    	public void Arrange(bool deterministic) {
    		Arrange(DEFAULT_DAMPING, DEFAULT_SPRING_LENGTH, DEFAULT_MAX_ITERATIONS, deterministic);
    	}
     
    	/// <summary>
    	/// Runs the force-directed layout algorithm on this Diagram, using the specified parameters.
    	/// </summary>
    	/// <param name="damping">Value between 0 and 1 that slows the motion of the nodes during layout.</param>
    	/// <param name="springLength">Value in pixels representing the length of the imaginary springs that run along the connectors.</param>
    	/// <param name="maxIterations">Maximum number of iterations before the algorithm terminates.</param>
    	/// <param name="deterministic">Whether to use a random or deterministic layout.</param>
    	public void Arrange(double damping, int springLength, int maxIterations, bool deterministic) {
    		// random starting positions can be made deterministic by seeding System.Random with a constant
    		Random rnd = deterministic ? new Random(0) : new Random();
     
    		// copy nodes into an array of metadata and randomise initial coordinates for each node
    		NodeLayoutInfo[] layout = new NodeLayoutInfo[mNodes.Count];
    		for (int i = 0; i < mNodes.Count; i++) {
    			layout[i] = new NodeLayoutInfo(mNodes[i], new Vector(), Point.Empty);
    			layout[i].Node.Location = new Point(rnd.Next(-50, 50), rnd.Next(-50, 50));
    		}
     
    		int stopCount = 0;
    		int iterations = 0;
     
    		while (true) {
    			double totalDisplacement = 0;
     
    			for (int i=0; i<layout.Length; i++) {
    				NodeLayoutInfo current = layout[i];
     
    				// express the node's current position as a vector, relative to the origin
    				Vector currentPosition = new Vector(CalcDistance(Point.Empty, current.Node.Location), GetBearingAngle(Point.Empty, current.Node.Location));
    				Vector netForce = new Vector(0, 0);
     
    				// determine repulsion between nodes
    				foreach (Node other in mNodes) {
    					if (other != current.Node) netForce += CalcRepulsionForce(current.Node, other);
    				}
     
    				// determine attraction caused by connections
    				foreach (Node child in current.Node.Connections) {
    					netForce += CalcAttractionForce(current.Node, child, springLength);
    				}
    				foreach (Node parent in mNodes) {
    					if (parent.Connections.Contains(current.Node)) netForce += CalcAttractionForce(current.Node, parent, springLength);
    				}
     
    				// apply net force to node velocity
    				current.Velocity = (current.Velocity + netForce) * damping;
     
    				// apply velocity to node position
    				current.NextPosition = (currentPosition + current.Velocity).ToPoint();
    			}
     
    			// move nodes to resultant positions (and calculate total displacement)
    			for (int i = 0; i < layout.Length; i++) {
    				NodeLayoutInfo current = layout[i];
     
    				totalDisplacement += CalcDistance(current.Node.Location, current.NextPosition);
    				current.Node.Location = current.NextPosition;
    			}
     
    			iterations++;
    			if (totalDisplacement < 10) stopCount++;
    			if (stopCount > 15) break;
    			if (iterations > maxIterations) break;
    		}
     
    		// center the diagram around the origin
    		Rectangle logicalBounds = GetDiagramBounds();
    		Point midPoint = new Point(logicalBounds.X + (logicalBounds.Width / 2), logicalBounds.Y + (logicalBounds.Height / 2));
     
    		foreach (Node node in mNodes) {
    			node.Location -= (Size)midPoint;
    		}
    	}
     
    	/// <summary>
    	/// Calculates the attraction force between two connected nodes, using the specified spring length.
    	/// </summary>
    	/// <param name="x">The node that the force is acting on.</param>
    	/// <param name="y">The node creating the force.</param>
    	/// <param name="springLength">The length of the spring, in pixels.</param>
    	/// <returns>A Vector representing the attraction force.</returns>
    	private Vector CalcAttractionForce(Node x, Node y, double springLength) {
    		int proximity = Math.Max(CalcDistance(x.Location, y.Location), 1);
     
    		// Hooke's Law: F = -kx
    		double force = ATTRACTION_CONSTANT * Math.Max(proximity - springLength, 0);
    		double angle = GetBearingAngle(x.Location, y.Location);
     
    		return new Vector(force, angle);
    	}
     
    	/// <summary>
    	/// Calculates the distance between two points.
    	/// </summary>
    	/// <param name="a">The first point.</param>
    	/// <param name="b">The second point.</param>
    	/// <returns>The pixel distance between the two points.</returns>
    	public static int CalcDistance(Point a, Point b) {
    		double xDist = (a.X - b.X);
    		double yDist = (a.Y - b.Y);
    		return (int)Math.Sqrt(Math.Pow(xDist, 2) + Math.Pow(yDist, 2));
    	}
     
    	/// <summary>
    	/// Calculates the repulsion force between any two nodes in the diagram space.
    	/// </summary>
    	/// <param name="x">The node that the force is acting on.</param>
    	/// <param name="y">The node creating the force.</param>
    	/// <returns>A Vector representing the repulsion force.</returns>
    	private Vector CalcRepulsionForce(Node x, Node y) {
    		int proximity = Math.Max(CalcDistance(x.Location, y.Location), 1);
     
    		// Coulomb's Law: F = k(Qq/r^2)
    		double force = -(REPULSION_CONSTANT / Math.Pow(proximity, 2));
    		double angle = GetBearingAngle(x.Location, y.Location);
     
    		return new Vector(force, angle);
    	}
     
    	/// <summary>
    	/// Removes all nodes and connections from the diagram.
    	/// </summary>
    	public void Clear() {
    		mNodes.Clear();
    	}
     
    	/// <summary>
    	/// Determines whether the diagram contains the specified node.
    	/// </summary>
    	/// <param name="node">The node to test.</param>
    	/// <returns>True if the diagram contains the node.</returns>
    	public bool ContainsNode(Node node) {
    		return mNodes.Contains(node);
    	}
     
    	/// <summary>
    	/// Draws the diagram using GDI+, centering and scaling within the specified bounds.
    	/// </summary>
    	/// <param name="graphics">GDI+ Graphics surface.</param>
    	/// <param name="bounds">Bounds in which to draw the diagram.</param>
    	public void Draw(Graphics graphics, Rectangle bounds) {
    		Point center = new Point(bounds.X + (bounds.Width / 2), bounds.Y + (bounds.Height / 2));
     
    		// determine the scaling factor
    		Rectangle logicalBounds = GetDiagramBounds();
    		double scale = 1;
    		if (logicalBounds.Width > logicalBounds.Height) {
    			if (logicalBounds.Width != 0) scale = (double)Math.Min(bounds.Width, bounds.Height) / (double)logicalBounds.Width;
    		}
    		else {
    			if (logicalBounds.Height != 0) scale = (double)Math.Min(bounds.Width, bounds.Height) / (double)logicalBounds.Height;
    		}
     
    		// draw all of the connectors first
    		foreach (Node node in mNodes) {
    			Point source = ScalePoint(node.Location, scale);
     
    			// connectors
    			foreach (Node other in node.Connections) {
    				Point destination = ScalePoint(other.Location, scale);
    				node.DrawConnector(graphics, center + (Size)source, center + (Size)destination, other);
    			}
    		}
     
    		// then draw all of the nodes
    		foreach (Node node in mNodes) {
    			Point destination = ScalePoint(node.Location, scale);
     
    			Size nodeSize = node.Size;
    			Rectangle nodeBounds = new Rectangle(center.X + destination.X - (nodeSize.Width / 2), center.Y + destination.Y - (nodeSize.Height / 2), nodeSize.Width, nodeSize.Height);
    			node.DrawNode(graphics, nodeBounds);
    		}
    	}
     
    	/// <summary>
    	/// Calculates the bearing angle from one point to another.
    	/// </summary>
    	/// <param name="start">The node that the angle is measured from.</param>
    	/// <param name="end">The node that creates the angle.</param>
    	/// <returns>The bearing angle, in degrees.</returns>
    	private double GetBearingAngle(Point start, Point end) {
    		Point half = new Point(start.X + ((end.X - start.X) / 2), start.Y + ((end.Y - start.Y) / 2));
     
    		double diffX = (double)(half.X - start.X);
    		double diffY = (double)(half.Y - start.Y);
     
    		if (diffX == 0) diffX = 0.001;
    		if (diffY == 0) diffY = 0.001;
     
    		double angle;
    		if (Math.Abs(diffX) > Math.Abs(diffY)) {
    			angle = Math.Tanh(diffY / diffX) * (180.0 / Math.PI);
    			if (((diffX < 0) && (diffY > 0)) || ((diffX < 0) && (diffY < 0))) angle += 180;
    		}
    		else {
    			angle = Math.Tanh(diffX / diffY) * (180.0 / Math.PI);
    			if (((diffY < 0) && (diffX > 0)) || ((diffY < 0) && (diffX < 0))) angle += 180;
    			angle = (180 - (angle + 90));
    		}
     
    		return angle;
    	}
     
    	/// <summary>
    	/// Determines the logical bounds of the diagram. This is used to center and scale the diagram when drawing.
    	/// </summary>
    	/// <returns>A System.Drawing.Rectangle that fits exactly around every node in the diagram.</returns>
    	private Rectangle GetDiagramBounds() {
    		int minX = Int32.MaxValue, minY = Int32.MaxValue;
    		int maxX = Int32.MinValue, maxY = Int32.MinValue;
    		foreach (Node node in mNodes) {
    			if (node.X < minX) minX = node.X;
    			if (node.X > maxX) maxX = node.X;
    			if (node.Y < minY) minY = node.Y;
    			if (node.Y > maxY) maxY = node.Y;
    		}
     
    		return Rectangle.FromLTRB(minX, minY, maxX, maxY);
    	}
     
    	/// <summary>
    	/// Removes the specified node from the diagram. Any connected nodes will remain on the diagram.
    	/// </summary>
    	/// <param name="node">The node to remove from the diagram.</param>
    	/// <returns>True if the node belonged to the diagram.</returns>
    	public bool RemoveNode(Node node) {
    		node.Diagram = null;
    		foreach (Node other in mNodes) {
    			if ((other != node) && other.Connections.Contains(node)) other.Disconnect(node);
    		}
    		return mNodes.Remove(node);
    	}
     
    	/// <summary>
    	/// Applies a scaling factor to the specified point, used for zooming.
    	/// </summary>
    	/// <param name="point">The coordinates to scale.</param>
    	/// <param name="scale">The scaling factor.</param>
    	/// <returns>A System.Drawing.Point representing the scaled coordinates.</returns>
    	private Point ScalePoint(Point point, double scale) {
    		return new Point((int)((double)point.X * scale), (int)((double)point.Y * scale));
    	}
     
    	/// <summary>
    	/// Private inner class used to track the node's position and velocity during simulation.
    	/// </summary>
    	private class NodeLayoutInfo {
     
    		public Node Node;			// reference to the node in the simulation
    		public Vector Velocity;		// the node's current velocity, expressed in vector form
    		public Point NextPosition;	// the node's position after the next iteration
     
    		/// <summary>
    		/// Initialises a new instance of the Diagram.NodeLayoutInfo class, using the specified parameters.
    		/// </summary>
    		/// <param name="node"></param>
    		/// <param name="velocity"></param>
    		/// <param name="nextPosition"></param>
    		public NodeLayoutInfo(Node node, Vector velocity, Point nextPosition) {
    			Node = node;
    			Velocity = velocity;
    			NextPosition = nextPosition;
    		}
    	}
    }
     
    //CODE DU WINFORM QUI L'UTILISE  
     
    // A Force-Directed Diagram Layout Algorithm
    // Bradley Smith - 2010/07/01
     
    // uncomment the following line to animate the iterations of the force-directed algorithm:
    //#define ANIMATE
     
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Threading;
     
     
    namespace ForceDirected {
     
    	public partial class Demo : Form {
     
    		Diagram mDiagram;
    		Random mRandom;
     
    		public Demo() {
    			InitializeComponent();
     
    			mDiagram = new Diagram();
    			mRandom = new Random();
    		}
     
    		protected override void OnPaint(PaintEventArgs e) {
    			base.OnPaint(e);
     
    			// draw with anti-aliasing and a 12 pixel border
    			e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
    			mDiagram.Draw(e.Graphics, Rectangle.FromLTRB(12, 12, ClientSize.Width - 12, ClientSize.Height - 12));
    		}
     
    		protected override void OnResize(EventArgs e) {
    			base.OnResize(e);
     
    			// redraw on resize
    			Invalidate();
    		}
     
    		private void btnGenerate_Click(object sender, EventArgs e) {
    			mDiagram.Clear();
     
    			// create a basic, random diagram that is between 2 and 4 levels deep 
    			// and has between 1 and 10 leaf nodes per branch
    			Node node = new SpotNode(Color.Black);
    			mDiagram.AddNode(node);
     
    			for (int i = 0; i < mRandom.Next(1, 10); i++) {
    				Node child = new SpotNode(Color.Navy);
    				node.AddChild(child);
     
    				for (int j = 0; j < mRandom.Next(0, 10); j++) {
    					Node grandchild = new SpotNode(Color.Blue);
    					child.AddChild(grandchild);
     
    					for (int k = 0; k < mRandom.Next(0, 10); k++) {
    						Node descendant = new SpotNode(Color.CornflowerBlue);
    						grandchild.AddChild(descendant);
    					}
    				}
    			}
     
    			// run the force-directed algorithm (async)
    			Cursor = Cursors.WaitCursor;
    			btnGenerate.Enabled = false;
    			Thread bg = new Thread(mDiagram.Arrange);
    			bg.IsBackground = true;
    			bg.Start();
     
    			Graphics g = CreateGraphics();
     
    #if ANIMATE
    			while (bg.IsAlive) {
    				Invalidate();
    				Application.DoEvents();
    				Thread.Sleep(20);
    			}
    #else
    			bg.Join();
    #endif
     
    			btnGenerate.Enabled = true;
    			Cursor = Cursors.Default;
     
    			Invalidate();
    		}
    	}
    }
    Ajouter les fichiers .cs a un projet Winform et generer.
    Si tu uncomment la directive #define ANIMATE les iterations sont animes....
    Amuse- toi avec les flottants et leurs deboires sous-jacents...
    bon implementation.......

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Formalisation graphique des algorithmes
    Par David R. dans le forum Algorithmes et structures de données
    Réponses: 14
    Dernier message: 08/12/2012, 10h21
  2. Algorithme de randomisation ... ( Hasard ...? )
    Par Anonymous dans le forum Assembleur
    Réponses: 8
    Dernier message: 06/09/2002, 14h25
  3. recherches des cours ou des explications sur les algorithmes
    Par Marcus2211 dans le forum Algorithmes et structures de données
    Réponses: 6
    Dernier message: 19/05/2002, 22h18
  4. Recherche de documentation complète en algorithmes
    Par Anonymous dans le forum Algorithmes et structures de données
    Réponses: 1
    Dernier message: 29/03/2002, 12h09
  5. Algorithme génétique
    Par Stephane.P_(dis Postef) dans le forum Algorithmes et structures de données
    Réponses: 2
    Dernier message: 15/03/2002, 17h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo