1 /** \file 2 * \brief Declaration of Fast Multipole Multilevel Method (FM^3). 3 * 4 * \author Stefan Hachul 5 * 6 * \par License: 7 * This file is part of the Open Graph Drawing Framework (OGDF). 8 * 9 * \par 10 * Copyright (C)<br> 11 * See README.md in the OGDF root directory for details. 12 * 13 * \par 14 * This program is free software; you can redistribute it and/or 15 * modify it under the terms of the GNU General Public License 16 * Version 2 or 3 as published by the Free Software Foundation; 17 * see the file LICENSE.txt included in the packaging of this file 18 * for details. 19 * 20 * \par 21 * This program is distributed in the hope that it will be useful, 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 * GNU General Public License for more details. 25 * 26 * \par 27 * You should have received a copy of the GNU General Public 28 * License along with this program; if not, see 29 * http://www.gnu.org/copyleft/gpl.html 30 */ 31 32 #pragma once 33 34 #include <ogdf/basic/Graph.h> 35 #include <ogdf/cluster/ClusterGraphAttributes.h> 36 #include <ogdf/basic/LayoutModule.h> 37 #include <ogdf/basic/geometry.h> 38 #include <ogdf/energybased/fmmm/NewMultipoleMethod.h> 39 #include <ogdf/energybased/fmmm/maar_packing/Rectangle.h> 40 41 namespace ogdf { 42 43 /** 44 * \brief The fast multipole multilevel layout algorithm. 45 * 46 * @ingroup gd-energy 47 * 48 * The class FMMMLayout implements a force-directed graph drawing 49 * method suited also for very large graphs. It is based on a 50 * combination of an efficient multilevel scheme and a strategy for 51 * approximating the repulsive forces in the system by rapidly 52 * evaluating potential fields. 53 * 54 * The implementation is based on the following publication: 55 * 56 * Stefan Hachul, Michael Jünger: <i>Drawing Large Graphs with a 57 * Potential-Field-Based Multilevel Algorithm</i>. 12th International 58 * Symposium on %Graph Drawing 1998, New York (GD '04), LNCS 3383, 59 * pp. 285-295, 2004. 60 * 61 * <H3>Optional parameters</H3> 62 * The following options are the most important. You can set 63 * useHighLevelOptions to true and just need to adjust a few parameters. 64 * However, you can also adjust all parameters that the implementation 65 * uses (see below), but this requires good knowledge of the algorithm. 66 * 67 * <table> 68 * <tr> 69 * <th><i>Option</i><th><i>Type</i><th><i>Default</i><th><i>Description</i> 70 * </tr><tr> 71 * <td><i>useHighLevelOptions</i><td>bool<td>false 72 * <td>Whether high-level options are used or not. 73 * </tr><tr> 74 * <td><i>pageFormat</i><td> FMMMOptions::PageFormatType <td> \c Square 75 * <td>The desired aspect ratio of the layout. 76 * </tr><tr> 77 * <td><i>unitEdgeLength</i><td>double<td>100.0 78 * <td>The unit edge length. 79 * </tr><tr> 80 * <td><i>newInitialPlacement</i><td>bool<td>false 81 * <td>Specifies if initial placement of nodes is varied. 82 * </tr><tr> 83 * <td><i>qualityVersusSpeed</i><td> FMMMOptions::QualityVsSpeed <td> \c BeautifulAndFast 84 * <td>Indicates if the algorithm is tuned either for best quality or best speed. 85 * </tr> 86 * </table> 87 * 88 * If you want to do more detailed fine-tuning, you can adjust all parameters 89 * used by the algorithm. Please refer to the paper cited above for better 90 * understanding of the algorithm. 91 * 92 * <table> 93 * <tr> 94 * <th colspan="4" align="center"><b>General</b> 95 * </tr><tr> 96 * <td><i>randSeed</i><td>int<td>100 97 * <td>The seed of the random number generator. 98 * </tr><tr> 99 * <td><i>edgeLengthMeasurement</i><td> FMMMOptions::EdgeLengthMeasurement <td> \c BoundingCircle 100 * <td>Indicates how the length of an edge is measured. 101 * </tr><tr> 102 * <td><i>allowedPositions</i><td> FMMMOptions::AllowedPositions <td> \c Integer 103 * <td>Defines which positions for a node are allowed. 104 * </tr><tr> 105 * <td><i>maxIntPosExponent</i><td>int<td>40 106 * <td>Defines the exponent used if allowedPositions == Exponent. 107 * </tr><tr> 108 * <th colspan="4" align="center"><b>Divide et impera step</b> 109 * </tr><tr> 110 * <td><i>pageRatio</i><td>double<td>1.0 111 * <td>The desired page ratio. 112 * </tr><tr> 113 * <td><i>stepsForRotatingComponents</i><td>int<td>10 114 * <td>The number of rotations per connected component. 115 * </tr><tr> 116 * <td><i>tipOverCCs</i><td> FMMMOptions::TipOver <td> \c NoGrowingRow 117 * <td>Specifies when it is allowed to tip over drawings. 118 * </tr><tr> 119 * <td><i>minDistCC</i><td>double<td>100 120 * <td>The minimal distance between connected components. 121 * </tr><tr> 122 * <td><i>presortCCs</i><td> FMMMOptions::PreSort <td> \c DecreasingHeight 123 * <td>Defines if the connected components are sorted before 124 * the packing algorithm is applied. 125 * </tr><tr> 126 * <th colspan="4" align="center"><b>Multilevel step</b> 127 * </tr><tr> 128 * <td><i>minGraphSize</i><td>int<td>50 129 * <td>Determines the number of nodes of a graph for which 130 * no more collapsing of galaxies is performed. 131 * </tr><tr> 132 * <td><i>galaxyChoice</i><td> FMMMOptions::GalaxyChoice <td> \c NonUniformProbLowerMass 133 * <td>Defines how sun nodes of galaxies are selected. 134 * </tr><tr> 135 * <td><i>randomTries</i><td>int<td>20 136 * <td>Defines the number of tries to get a random node with 137 * minimal star mass. 138 * </tr><tr> 139 * <td><i>maxIterChange</i><td> FMMMOptions::MaxIterChange <td> \c LinearlyDecreasing 140 * <td>Defines how MaxIterations is changed in subsequent multilevels. 141 * </tr><tr> 142 * <td><i>maxIterFactor</i><td>int<td>10 143 * <td>Defines the factor used for decreasing MaxIterations. 144 * </tr><tr> 145 * <td><i>initialPlacementMult</i><td> FMMMOptions::InitialPlacementMult <td> \c Advanced 146 * <td>Defines how the initial placement is generated. 147 * </tr><tr> 148 * <th colspan="4" align="center"><b>Force calculation step</b> 149 * </tr><tr> 150 * <td><i>forceModel</i><td> FMMMOptions::ForceModel <td> \c New 151 * <td>The used force model. 152 * </tr><tr> 153 * <td><i>springStrength</i><td>double<td>1.0 154 * <td>The strength of the springs. 155 * </tr><tr> 156 * <td><i>repForcesStrength</i><td>double<td>1.0 157 * <td>The strength of the repulsive forces. 158 * </tr><tr> 159 * <td><i>repulsiveForcesCalculation</i><td> FMMMOptions::RepulsiveForcesMethod <td> \c NMM 160 * <td>Defines how to calculate repulsive forces. 161 * </tr><tr> 162 * <td><i>stopCriterion</i><td> FMMMOptions::StopCriterion <td> \c FixedIterationsOrThreshold 163 * <td>The stop criterion. 164 * </tr><tr> 165 * <td><i>threshold</i><td>double<td>0.01 166 * <td>The threshold for the stop criterion. 167 * </tr><tr> 168 * <td><i>fixedIterations</i><td>int<td>30 169 * <td>The fixed number of iterations for the stop criterion. 170 * </tr><tr> 171 * <td><i>forceScalingFactor</i><td>double<td>0.05 172 * <td>The scaling factor for the forces. 173 * </tr><tr> 174 * <td><i>coolTemperature</i><td>bool<td>false 175 * <td>Use coolValue for scaling forces. 176 * </tr><tr> 177 * <td><i>coolValue</i><td>double<td>0.99 178 * <td>The value by which forces are decreased. 179 * </tr><tr> 180 * <td><i>initialPlacementForces</i><td> FMMMOptions::InitialPlacementForces <td> \c RandomRandIterNr 181 * <td>Defines how the initial placement is done. 182 * </tr><tr> 183 * <th colspan="4" align="center"><b>Force calculation step</b> 184 * </tr><tr> 185 * <td><i>resizeDrawing</i><td>bool<td>true 186 * <td>Specifies if the resulting drawing is resized. 187 * </tr><tr> 188 * <td><i>resizingScalar</i><td>double<td>1 189 * <td>Defines a parameter to scale the drawing if resizeDrawing is true. 190 * </tr><tr> 191 * <td><i>fineTuningIterations</i><td>int<td>20 192 * <td>The number of iterations for fine tuning. 193 * </tr><tr> 194 * <td><i>fineTuneScalar</i><td>double<td>0.2 195 * <td>Defines a parameter for scaling the forces in the fine-tuning iterations. 196 * </tr><tr> 197 * <td><i>adjustPostRepStrengthDynamically</i><td>bool<td>true 198 * <td>If set to true, the strength of the repulsive force field is calculated. 199 * </tr><tr> 200 * <td><i>postSpringStrength</i><td>double<td>2.0 201 * <td>The strength of the springs in the postprocessing step. 202 * </tr><tr> 203 * <td><i>postStrengthOfRepForces</i><td>double<td>0.01 204 * <td>The strength of the repulsive forces in the postprocessing step. 205 * </tr><tr> 206 * <th colspan="4" align="center"><b>Repulsive force approximation methods</b> 207 * </tr><tr> 208 * <td><i>frGridQuotient</i><td>int<td>2 209 * <td>The grid quotient. 210 * </tr><tr> 211 * <td><i>nmTreeConstruction</i><td> FMMMOptions::ReducedTreeConstruction <td> \c SubtreeBySubtree 212 * <td>Defines how the reduced bucket quadtree is constructed. 213 * </tr><tr> 214 * <td><i>nmSmallCell</i><td> FMMMOptions::SmallestCellFinding <td> \c Iteratively 215 * <td>Defines how the smallest quadratic cell that surrounds 216 * the particles of a node in the reduced bucket quadtree is calculated. 217 * </tr><tr> 218 * <td><i>nmParticlesInLeaves</i><td>int<td>25 219 * <td>The maximal number of particles that are contained in 220 * a leaf of the reduced bucket quadtree. 221 * </tr><tr> 222 * <td><i>nmPrecision</i><td>int<td>4 223 * <td>The precision \a p for the <i>p</i>-term multipole expansions. 224 * </tr> 225 * </table> 226 * 227 * <H3>Running time</H3> 228 * The running time of the algorithm is 229 * O(<i>n</i> log <i>n</i> + <i>m</i>) for graphs with \a n nodes 230 * and \a m edges. The required space is linear in the input size. 231 */ 232 class OGDF_EXPORT FMMMLayout : public LayoutModule 233 { 234 using Rectangle = energybased::fmmm::Rectangle; 235 using NodeAttributes = energybased::fmmm::NodeAttributes; 236 using EdgeAttributes = energybased::fmmm::EdgeAttributes; 237 238 public: 239 //! Creates an instance of the layout algorithm. 240 FMMMLayout(); 241 242 // destructor ~FMMMLayout()243 virtual ~FMMMLayout() { } 244 245 246 /** 247 * @name The algorithm call 248 * @{ 249 */ 250 251 //! Calls the algorithm for graph \p GA and returns the layout information in \p GA. 252 virtual void call(GraphAttributes &GA) override; 253 254 //! Calls the algorithm for clustered graph \p GA and returns the layout information in \p GA. 255 //! Models cluster by simple edge length adaption based on least common ancestor 256 //! cluster of end vertices. 257 void call(ClusterGraphAttributes &GA); 258 259 //! Extended algorithm call: Allows to pass desired lengths of the edges. 260 /** 261 * @param GA represents the input graph and is assigned the computed layout. 262 * @param edgeLength is an edge array of the graph associated with \p GA 263 * of positive edge length. 264 */ 265 void call( 266 GraphAttributes &GA, //graph and layout 267 const EdgeArray<double> &edgeLength); //factor for desired edge lengths 268 269 //! Extended algorithm call: Calls the algorithm for graph \p GA. 270 /** 271 * Returns layout information in \p GA and a simple drawing is saved in file \p ps_file 272 * in postscript format (Nodes are drawn as uniformly sized circles). 273 */ 274 void call(GraphAttributes &GA, char* ps_file); 275 276 //! Extend algorithm call: Allows to pass desired lengths of the edges. 277 /** 278 * The EdgeArray \p edgeLength must be valid for GA.constGraph() and its values must 279 * be positive. 280 * A simple drawing is saved in file ps_file in postscript format (Nodes are drawn 281 * as uniformly sized circles). 282 */ 283 void call( 284 GraphAttributes &GA, //graph and layout 285 const EdgeArray<double> &edgeLength, //factor for desired edge lengths 286 char* ps_file); 287 288 /** @} 289 * @name Further information. 290 * @{ 291 */ 292 293 //! Returns the runtime (=CPU-time) of the layout algorithm in seconds. getCpuTime()294 double getCpuTime() { 295 return time_total; 296 } 297 298 299 /** @} 300 * @name High-level options 301 * Allow to specify the most relevant parameters. 302 * @{ 303 */ 304 305 //! Returns the current setting of option useHighLevelOptions. 306 /** 307 * If set to true, the high-level options are used to set all low-level options. 308 * Usually, it is sufficient just to set high-level options; if you want to 309 * be more specific, set this parameter to false and set the low level options. 310 */ useHighLevelOptions()311 bool useHighLevelOptions() const { return m_useHighLevelOptions; } 312 313 //! Sets the option useHighLevelOptions to \p uho. useHighLevelOptions(bool uho)314 void useHighLevelOptions(bool uho) { m_useHighLevelOptions = uho; } 315 316 //! Sets single level option, no multilevel hierarchy is created if b == true setSingleLevel(bool b)317 void setSingleLevel(bool b) {m_singleLevel = b;} 318 319 //! Returns the current setting of option pageFormat. pageFormat()320 FMMMOptions::PageFormatType pageFormat() const { return m_pageFormat; } 321 322 //! Sets the option pageRatio to \p t. pageFormat(FMMMOptions::PageFormatType t)323 void pageFormat(FMMMOptions::PageFormatType t) { m_pageFormat = t; } 324 325 //! Returns the current setting of option unitEdgeLength. unitEdgeLength()326 double unitEdgeLength() const { return m_unitEdgeLength; } 327 328 //! Sets the option unitEdgeLength to \p x. unitEdgeLength(double x)329 void unitEdgeLength(double x) {m_unitEdgeLength = (( x > 0.0) ? x : 1);} 330 331 //! Returns the current setting of option newInitialPlacement. 332 /** 333 * This option defines if the initial placement of the nodes at the 334 * coarsest multilevel is varied for each distinct call of FMMMLayout 335 * or keeps always the same. 336 */ newInitialPlacement()337 bool newInitialPlacement() const { return m_newInitialPlacement; } 338 339 //! Sets the option newInitialPlacement to \p nip. newInitialPlacement(bool nip)340 void newInitialPlacement(bool nip) { m_newInitialPlacement = nip; } 341 342 //! Returns the current setting of option qualityVersusSpeed. qualityVersusSpeed()343 FMMMOptions::QualityVsSpeed qualityVersusSpeed() const { return m_qualityVersusSpeed; } 344 345 //! Sets the option qualityVersusSpeed to \p qvs. qualityVersusSpeed(FMMMOptions::QualityVsSpeed qvs)346 void qualityVersusSpeed(FMMMOptions::QualityVsSpeed qvs) {m_qualityVersusSpeed = qvs; } 347 348 349 /** @} 350 * @name General low-level options 351 * The low-level options in this and the following sections are meant for 352 * experts or interested people only. 353 * @{ 354 */ 355 356 //! Sets the seed of the random number generator. randSeed(int p)357 void randSeed(int p) { m_randSeed = ((0<=p) ? p : 1);} 358 359 //! Returns the seed of the random number generator. randSeed()360 int randSeed() const {return m_randSeed;} 361 362 //! Returns the current setting of option edgeLengthMeasurement. edgeLengthMeasurement()363 FMMMOptions::EdgeLengthMeasurement edgeLengthMeasurement() const { 364 return m_edgeLengthMeasurement; 365 } 366 367 //! Sets the option edgeLengthMeasurement to \p elm. edgeLengthMeasurement(FMMMOptions::EdgeLengthMeasurement elm)368 void edgeLengthMeasurement(FMMMOptions::EdgeLengthMeasurement elm) { m_edgeLengthMeasurement = elm; } 369 370 //! Returns the current setting of option allowedPositions. allowedPositions()371 FMMMOptions::AllowedPositions allowedPositions() const { return m_allowedPositions; } 372 373 //! Sets the option allowedPositions to \p ap. allowedPositions(FMMMOptions::AllowedPositions ap)374 void allowedPositions(FMMMOptions::AllowedPositions ap) { m_allowedPositions = ap; } 375 376 //! Returns the current setting of option maxIntPosExponent. 377 /** 378 * This option defines the exponent used if allowedPositions() == FMMMOptions::AllowedPositions::Exponent. 379 */ maxIntPosExponent()380 int maxIntPosExponent() const { return m_maxIntPosExponent; } 381 382 //! Sets the option maxIntPosExponent to \p e. maxIntPosExponent(int e)383 void maxIntPosExponent(int e) { 384 m_maxIntPosExponent = (((e >= 31)&&(e<=51))? e : 31); 385 } 386 387 388 /** @} 389 * @name Options for the divide et impera step 390 * @{ 391 */ 392 393 //! Returns the current setting of option pageRatio. 394 /** 395 * This option defines the desired aspect ratio of the rectangular drawing area. 396 */ pageRatio()397 double pageRatio() const { return m_pageRatio; } 398 399 //! Sets the option pageRatio to \p r. pageRatio(double r)400 void pageRatio(double r) {m_pageRatio = (( r > 0) ? r : 1);} 401 402 //! Returns the current setting of option stepsForRotatingComponents. 403 /** 404 * This options determines the number of times each connected component is rotated with 405 * angles between 0 and 90 degree to obtain a bounding rectangle with small area. 406 */ stepsForRotatingComponents()407 int stepsForRotatingComponents() const { return m_stepsForRotatingComponents; } 408 409 //! Sets the option stepsForRotatingComponents to \p n. stepsForRotatingComponents(int n)410 void stepsForRotatingComponents(int n) { 411 m_stepsForRotatingComponents = ((0<=n) ? n : 0); 412 } 413 414 //! Returns the current setting of option tipOverCCs. tipOverCCs()415 FMMMOptions::TipOver tipOverCCs() const { return m_tipOverCCs; } 416 417 //! Sets the option tipOverCCs to \p to. tipOverCCs(FMMMOptions::TipOver to)418 void tipOverCCs(FMMMOptions::TipOver to) { m_tipOverCCs = to; } 419 420 //! Returns the minimal distance between connected components. minDistCC()421 double minDistCC() const { return m_minDistCC; } 422 423 //! Sets the minimal distance between connected components to \p x. minDistCC(double x)424 void minDistCC(double x) { m_minDistCC = (( x > 0) ? x : 1);} 425 426 //! Returns the current setting of option presortCCs. presortCCs()427 FMMMOptions::PreSort presortCCs() const { return m_presortCCs; } 428 429 //! Sets the option presortCCs to \p ps. presortCCs(FMMMOptions::PreSort ps)430 void presortCCs(FMMMOptions::PreSort ps) { m_presortCCs = ps; } 431 432 433 /** @} 434 * @name Options for the multilevel step 435 * @{ 436 */ 437 438 //! Returns the current setting of option minGraphSize. 439 /** 440 * This option determines the number of nodes of a graph in the 441 * multilevel representation for which no more collapsing of galaxies 442 * is performed (i.e. the graph at the highest level). 443 */ minGraphSize()444 int minGraphSize() const { return m_minGraphSize; } 445 446 //! Sets the option minGraphSize to \p n. minGraphSize(int n)447 void minGraphSize(int n) { m_minGraphSize = ((n >= 2)? n : 2);} 448 449 //! Returns the current setting of option galaxyChoice. galaxyChoice()450 FMMMOptions::GalaxyChoice galaxyChoice() const { return m_galaxyChoice; } 451 452 //! Sets the option galaxyChoice to \p gc. galaxyChoice(FMMMOptions::GalaxyChoice gc)453 void galaxyChoice(FMMMOptions::GalaxyChoice gc) { m_galaxyChoice = gc; } 454 455 //! Returns the current setting of option randomTries. 456 /** 457 * This option defines the number of tries to get a random node with 458 * minimal star mass (used in case of galaxyChoice() == NonUniformProbLowerMass 459 * and galaxyChoice() == NonUniformProbHigherMass). 460 */ randomTries()461 int randomTries() const { return m_randomTries; } 462 463 //! Sets the option randomTries to \p n. randomTries(int n)464 void randomTries(int n) {m_randomTries = ((n>=1)? n: 1);} 465 466 //! Returns the current setting of option maxIterChange. maxIterChange()467 FMMMOptions::MaxIterChange maxIterChange() const { return m_maxIterChange; } 468 469 //! Sets the option maxIterChange to \p mic. maxIterChange(FMMMOptions::MaxIterChange mic)470 void maxIterChange(FMMMOptions::MaxIterChange mic) { m_maxIterChange = mic; } 471 472 //! Returns the current setting of option maxIterFactor. 473 /** 474 * This option defines the factor used for decrasing MaxIterations 475 * (in case of maxIterChange() == LinearlyDecreasing or maxIterChange() 476 * == RapidlyDecreasing). 477 */ maxIterFactor()478 int maxIterFactor() const { return m_maxIterFactor; } 479 480 //! Sets the option maxIterFactor to \p f. maxIterFactor(int f)481 void maxIterFactor(int f) { m_maxIterFactor = ((f>=1) ? f : 1 ); } 482 483 //! Returns the current setting of option initialPlacementMult. initialPlacementMult()484 FMMMOptions::InitialPlacementMult initialPlacementMult() const { 485 return m_initialPlacementMult; 486 } 487 488 //! Sets the option initialPlacementMult to \p ipm. initialPlacementMult(FMMMOptions::InitialPlacementMult ipm)489 void initialPlacementMult(FMMMOptions::InitialPlacementMult ipm) { 490 m_initialPlacementMult = ipm; 491 } 492 493 494 /** @} 495 * @name Options for the force calculation step 496 * @{ 497 */ 498 499 //! Returns the used force model. forceModel()500 FMMMOptions::ForceModel forceModel() const { return m_forceModel; } 501 502 //! Sets the used force model to \p fm. forceModel(FMMMOptions::ForceModel fm)503 void forceModel(FMMMOptions::ForceModel fm) { m_forceModel = fm; } 504 505 //! Returns the strength of the springs. springStrength()506 double springStrength() const { return m_springStrength; } 507 508 //! Sets the strength of the springs to \p x. springStrength(double x)509 void springStrength(double x) { m_springStrength = ((x > 0)? x : 1);} 510 511 //! Returns the strength of the repulsive forces. repForcesStrength()512 double repForcesStrength() const { return m_repForcesStrength; } 513 514 //! Sets the strength of the repulsive forces to \p x. repForcesStrength(double x)515 void repForcesStrength(double x) { m_repForcesStrength =((x > 0)? x : 1);} 516 517 //! Returns the current setting of option repulsiveForcesCalculation. repulsiveForcesCalculation()518 FMMMOptions::RepulsiveForcesMethod repulsiveForcesCalculation() const { 519 return m_repulsiveForcesCalculation; 520 } 521 522 //! Sets the option repulsiveForcesCalculation to \p rfc. repulsiveForcesCalculation(FMMMOptions::RepulsiveForcesMethod rfc)523 void repulsiveForcesCalculation(FMMMOptions::RepulsiveForcesMethod rfc) { 524 m_repulsiveForcesCalculation = rfc; 525 } 526 527 //! Returns the stop criterion. stopCriterion()528 FMMMOptions::StopCriterion stopCriterion() const { return m_stopCriterion; } 529 530 //! Sets the stop criterion to \p rsc. stopCriterion(FMMMOptions::StopCriterion rsc)531 void stopCriterion(FMMMOptions::StopCriterion rsc) { m_stopCriterion = rsc; } 532 533 //! Returns the threshold for the stop criterion. 534 /** 535 * (If the average absolute value of all forces in 536 * an iteration is less then threshold() then stop.) 537 */ threshold()538 double threshold() const { return m_threshold; } 539 540 //! Sets the threshold for the stop criterion to \p x. threshold(double x)541 void threshold(double x) {m_threshold = ((x > 0) ? x : 0.1);} 542 543 //! Returns the fixed number of iterations for the stop criterion. fixedIterations()544 int fixedIterations() const { return m_fixedIterations; } 545 546 //! Sets the fixed number of iterations for the stop criterion to \p n. fixedIterations(int n)547 void fixedIterations(int n) { m_fixedIterations = ((n >= 1) ? n : 1);} 548 549 //! Returns the scaling factor for the forces. forceScalingFactor()550 double forceScalingFactor() const { return m_forceScalingFactor; } 551 552 //! Sets the scaling factor for the forces to \p f. forceScalingFactor(double f)553 void forceScalingFactor(double f) { m_forceScalingFactor = ((f > 0) ? f : 1);} 554 555 //! Returns the current setting of option coolTemperature. 556 /** 557 * If set to true, forces are scaled by coolValue()^(actual iteration) * 558 * forceScalingFactor(); otherwise forces are scaled by forceScalingFactor(). 559 */ coolTemperature()560 bool coolTemperature() const { return m_coolTemperature; } 561 562 //! Sets the option coolTemperature to \p b. coolTemperature(bool b)563 void coolTemperature(bool b) { m_coolTemperature = b; } 564 565 //! Returns the current setting of option coolValue. 566 /** 567 * This option defines the value by which forces are decreased 568 * if coolTemperature is true. 569 */ coolValue()570 double coolValue() const { return m_coolValue; } 571 572 //! Sets the option coolValue to \p x. coolValue(double x)573 void coolValue(double x) { m_coolValue = (((x >0 )&&(x<=1) )? x : 0.99);} 574 575 576 //! Returns the current setting of option initialPlacementForces. initialPlacementForces()577 FMMMOptions::InitialPlacementForces initialPlacementForces() const { 578 return m_initialPlacementForces; 579 } 580 581 //! Sets the option initialPlacementForces to \p ipf. initialPlacementForces(FMMMOptions::InitialPlacementForces ipf)582 void initialPlacementForces(FMMMOptions::InitialPlacementForces ipf) { 583 m_initialPlacementForces = ipf; 584 } 585 586 587 /** @} 588 * @name Options for the postprocessing step 589 * @{ 590 */ 591 592 //! Returns the current setting of option resizeDrawing. 593 /** 594 * If set to true, the resulting drawing is resized so that the average edge 595 * length is the desired edge length times resizingScalar(). 596 */ resizeDrawing()597 bool resizeDrawing() const { return m_resizeDrawing; } 598 599 //! Sets the option resizeDrawing to \p b. resizeDrawing(bool b)600 void resizeDrawing(bool b) { m_resizeDrawing = b; } 601 602 //! Returns the current setting of option resizingScalar. 603 /** 604 * This option defines a parameter to scale the drawing if 605 * resizeDrawing() is true. 606 */ resizingScalar()607 double resizingScalar() const { return m_resizingScalar; } 608 609 //! Sets the option resizingScalar to \p s. resizingScalar(double s)610 void resizingScalar(double s) { m_resizingScalar = ((s > 0) ? s : 1);} 611 612 //! Returns the number of iterations for fine tuning. fineTuningIterations()613 int fineTuningIterations() const { return m_fineTuningIterations; } 614 615 //! Sets the number of iterations for fine tuning to \p n. fineTuningIterations(int n)616 void fineTuningIterations(int n) { m_fineTuningIterations =((n >= 0) ? n : 0);} 617 618 //! Returns the curent setting of option fineTuneScalar. 619 /** 620 * This option defines a parameter for scaling the forces in the 621 * fine-tuning iterations. 622 */ fineTuneScalar()623 double fineTuneScalar() const { return m_fineTuneScalar; } 624 625 //! Sets the option fineTuneScalar to \p s fineTuneScalar(double s)626 void fineTuneScalar(double s) { m_fineTuneScalar = ((s >= 0) ? s : 1);} 627 628 //! Returns the current setting of option adjustPostRepStrengthDynamically. 629 /** 630 * If set to true, the strength of the repulsive force field is calculated 631 * dynamically by a formula depending on the number of nodes; otherwise the 632 * strength are scaled by PostSpringStrength and PostStrengthOfRepForces. 633 */ adjustPostRepStrengthDynamically()634 bool adjustPostRepStrengthDynamically() const { 635 return m_adjustPostRepStrengthDynamically; 636 } 637 638 //! Sets the option adjustPostRepStrengthDynamically to \p b. adjustPostRepStrengthDynamically(bool b)639 void adjustPostRepStrengthDynamically(bool b) { 640 m_adjustPostRepStrengthDynamically = b; 641 } 642 643 //! Returns the strength of the springs in the postprocessing step. postSpringStrength()644 double postSpringStrength() const { return m_postSpringStrength; } 645 646 //! Sets the strength of the springs in the postprocessing step to \p x. postSpringStrength(double x)647 void postSpringStrength(double x) { m_postSpringStrength = ((x > 0)? x : 1);} 648 649 //! Returns the strength of the repulsive forces in the postprocessing step. postStrengthOfRepForces()650 double postStrengthOfRepForces() const { return m_postStrengthOfRepForces; } 651 652 //! Sets the strength of the repulsive forces in the postprocessing step to \p x. postStrengthOfRepForces(double x)653 void postStrengthOfRepForces(double x) { 654 m_postStrengthOfRepForces = ((x > 0)? x : 1); 655 } 656 657 658 /** @} 659 * @name Options for repulsive force approximation methods 660 * @{ 661 */ 662 663 //! Returns the current setting of option frGridQuotient. 664 /** 665 * The number k of rows and columns of the grid is sqrt(|V|) / frGridQuotient(). 666 * (Note that in [Fruchterman,Reingold] frGridQuotient is 2.) 667 */ frGridQuotient()668 int frGridQuotient() const {return m_frGridQuotient;} 669 670 //! Sets the option frGridQuotient to \p p. frGridQuotient(int p)671 void frGridQuotient(int p) { m_frGridQuotient = ((0<=p) ? p : 2);} 672 673 //! Returns the current setting of option nmTreeConstruction. nmTreeConstruction()674 FMMMOptions::ReducedTreeConstruction nmTreeConstruction() const { return m_NMTreeConstruction; } 675 676 //! Sets the option nmTreeConstruction to \p rtc. nmTreeConstruction(FMMMOptions::ReducedTreeConstruction rtc)677 void nmTreeConstruction(FMMMOptions::ReducedTreeConstruction rtc) { m_NMTreeConstruction = rtc; } 678 679 //! Returns the current setting of option nmSmallCell. nmSmallCell()680 FMMMOptions::SmallestCellFinding nmSmallCell() const { return m_NMSmallCell; } 681 682 //! Sets the option nmSmallCell to \p scf. nmSmallCell(FMMMOptions::SmallestCellFinding scf)683 void nmSmallCell(FMMMOptions::SmallestCellFinding scf) { m_NMSmallCell = scf; } 684 685 //! Returns the current setting of option nmParticlesInLeaves. 686 /** 687 * Defines the maximal number of particles that are contained in 688 * a leaf of the reduced bucket quadtree. 689 */ nmParticlesInLeaves()690 int nmParticlesInLeaves() const { return m_NMParticlesInLeaves; } 691 692 //! Sets the option nmParticlesInLeaves to \p n. nmParticlesInLeaves(int n)693 void nmParticlesInLeaves(int n) { m_NMParticlesInLeaves = ((n>= 1)? n : 1);} 694 695 //! Returns the precision \a p for the <i>p</i>-term multipole expansions. nmPrecision()696 int nmPrecision() const { return m_NMPrecision; } 697 698 //! Sets the precision for the multipole expansions to \p p. nmPrecision(int p)699 void nmPrecision(int p) { m_NMPrecision = ((p >= 1 ) ? p : 1);} 700 701 //! @} 702 703 private: 704 705 //high level options 706 bool m_useHighLevelOptions; //!< The option for using high-level options. 707 FMMMOptions::PageFormatType m_pageFormat; //!< The option for the page format. 708 double m_unitEdgeLength; //!< The unit edge length. 709 bool m_newInitialPlacement; //!< The option for new initial placement. 710 FMMMOptions::QualityVsSpeed m_qualityVersusSpeed; //!< The option for quality-vs-speed trade-off. 711 712 //low level options 713 //general options 714 int m_randSeed; //!< The random seed. 715 FMMMOptions::EdgeLengthMeasurement m_edgeLengthMeasurement; //!< The option for edge length measurement. 716 FMMMOptions::AllowedPositions m_allowedPositions; //!< The option for allowed positions. 717 int m_maxIntPosExponent; //!< The option for the used exponent. 718 719 //options for divide et impera step 720 double m_pageRatio; //!< The desired page ratio. 721 int m_stepsForRotatingComponents; //!< The number of rotations. 722 FMMMOptions::TipOver m_tipOverCCs; //!< Option for tip-over of connected components. 723 double m_minDistCC; //!< The separation between connected components. 724 FMMMOptions::PreSort m_presortCCs; //!< The option for presorting connected components. 725 726 //options for multilevel step 727 bool m_singleLevel; //!< Option for pure single level. 728 int m_minGraphSize; //!< The option for minimal graph size. 729 FMMMOptions::GalaxyChoice m_galaxyChoice; //!< The selection of galaxy nodes. 730 int m_randomTries; //!< The number of random tries. 731 732 //! The option for how to change MaxIterations. 733 //! If maxIterChange != micConstant, the iterations are decreased 734 //! depending on the level, starting from 735 //! ((maxIterFactor()-1) * fixedIterations()) 736 FMMMOptions::MaxIterChange m_maxIterChange; 737 738 int m_maxIterFactor; //!< The factor used for decreasing MaxIterations. 739 FMMMOptions::InitialPlacementMult m_initialPlacementMult; //!< The option for creating initial placement. 740 741 //options for force calculation step 742 FMMMOptions::ForceModel m_forceModel; //!< The used force model. 743 double m_springStrength; //!< The strengths of springs. 744 double m_repForcesStrength; //!< The strength of repulsive forces. 745 FMMMOptions::RepulsiveForcesMethod m_repulsiveForcesCalculation; //!< Option for how to calculate repulsive forces. 746 FMMMOptions::StopCriterion m_stopCriterion; //!< The stop criterion. 747 double m_threshold; //!< The threshold for the stop criterion. 748 int m_fixedIterations; //!< The fixed number of iterations for the stop criterion. 749 double m_forceScalingFactor; //!< The scaling factor for the forces. 750 bool m_coolTemperature; //!< The option for how to scale forces. 751 double m_coolValue; //!< The value by which forces are decreased. 752 FMMMOptions::InitialPlacementForces m_initialPlacementForces; //!< The option for how the initial placement is done. 753 754 //options for postprocessing step 755 bool m_resizeDrawing; //!< The option for resizing the drawing. 756 double m_resizingScalar; //!< Parameter for resizing the drawing. 757 int m_fineTuningIterations; //!< The number of iterations for fine tuning. 758 double m_fineTuneScalar; //!< Parameter for scaling forces during fine tuning. 759 bool m_adjustPostRepStrengthDynamically; //!< The option adjustPostRepStrengthDynamically. 760 double m_postSpringStrength; //!< The strength of springs during postprocessing. 761 double m_postStrengthOfRepForces; //!< The strength of repulsive forces during postprocessing. 762 763 //options for repulsive force approximation methods 764 int m_frGridQuotient; //!< The grid quotient. 765 FMMMOptions::ReducedTreeConstruction m_NMTreeConstruction; //!< The option for how to construct reduced bucket quadtree. 766 FMMMOptions::SmallestCellFinding m_NMSmallCell; //!< The option for how to calculate smallest quadtratic cells. 767 int m_NMParticlesInLeaves; //!< The maximal number of particles in a leaf. 768 int m_NMPrecision; //!< The precision for multipole expansions. 769 770 //other variables 771 double max_integer_position; //!< The maximum value for an integer position. 772 double cool_factor; //!< Needed for scaling the forces if coolTemperature is true. 773 double average_ideal_edgelength; //!< Measured from center to center. 774 double boxlength; //!< Holds the length of the quadratic comput. box. 775 int number_of_components; //!< The number of components of the graph. 776 DPoint down_left_corner; //!< Holds down left corner of the comput. box. 777 NodeArray<double> radius; //!< Holds the radius of the surrounding circle for each node. 778 double time_total; //!< The runtime (=CPU-time) of the algorithm in seconds. 779 780 energybased::fmmm::FruchtermanReingold FR; //!< Class for repulsive force calculation (Fruchterman, Reingold). 781 energybased::fmmm::NewMultipoleMethod NM; //!< Class for repulsive force calculation. 782 783 //! \name Most important functions 784 //! @{ 785 786 //! Calls the divide (decomposition into connected components) and impera (drawing and packing of the componenets) step. 787 void call_DIVIDE_ET_IMPERA_step( 788 Graph& G, 789 NodeArray<NodeAttributes>& A, 790 EdgeArray<EdgeAttributes>& E); 791 792 //! Calls the multilevel step for subGraph \p G. 793 void call_MULTILEVEL_step_for_subGraph( 794 Graph& G, 795 NodeArray<NodeAttributes>& A, 796 EdgeArray<EdgeAttributes>& E); 797 798 //! Returns true iff stopCriterion() is not met 799 bool running(int iter, int max_mult_iter, double actforcevectorlength); 800 801 //! Calls the force calculation step for \p G, \p A, \p E. 802 /** 803 * If act_level is 0 and resizeDrawing is true the drawing is resized. 804 * Furthermore, the maximum number of force calc. steps is calculated 805 * depending on MaxIterChange, act_level, and max_level. 806 */ 807 void call_FORCE_CALCULATION_step ( 808 Graph& G, 809 NodeArray<NodeAttributes>& A, 810 EdgeArray<EdgeAttributes>& E, 811 int act_level, 812 int max_level); 813 814 //! Calls the postprocessing step. 815 void call_POSTPROCESSING_step( 816 Graph& G, 817 NodeArray<NodeAttributes>& A, 818 EdgeArray<EdgeAttributes>& E, 819 NodeArray<DPoint>& F, 820 NodeArray<DPoint>& F_attr, 821 NodeArray<DPoint>& F_rep, 822 NodeArray<DPoint>& last_node_movement); 823 824 //! @} 825 //! \name Functions for pre- and post-processing 826 //! @{ 827 828 //! All parameter options are set to the default values. 829 void initialize_all_options(); 830 831 //! Updates several low level parameter options due to the settings of the high level parameter options. 832 void update_low_level_options_due_to_high_level_options_settings(); 833 834 //! Imports for each node \a v of \p G its width, height and position (given from \p GA) in \p A. 835 void import_NodeAttributes( 836 const Graph& G, 837 GraphAttributes& GA, 838 NodeArray<NodeAttributes>& A); 839 840 //! Imports for each edge e of G its desired length given via edgeLength. 841 void import_EdgeAttributes ( 842 const Graph& G, 843 const EdgeArray<double>& edgeLength, 844 EdgeArray <EdgeAttributes>& E); 845 846 //! Sets the individual ideal edge length for each edge \a e. 847 void init_ind_ideal_edgelength( 848 const Graph& G, 849 NodeArray<NodeAttributes>&A, 850 EdgeArray <EdgeAttributes>& E); 851 852 //! The radii of the surrounding circles of the bounding boxes are computed. 853 void set_radii(const Graph& G,NodeArray<NodeAttributes>& A); 854 855 //! Exports for each node \a v in \p G_reduced the position of the original_node in \p GA. 856 void export_NodeAttributes( 857 Graph& G_reduced, 858 NodeArray<NodeAttributes>& A_reduced, 859 GraphAttributes& GA); 860 861 //! Creates a simple and loopfree copy of \p G and stores the corresponding node / edge attributes. 862 /** 863 * The corresponding node / edge attributes are stored in \p A_reduced and 864 * \p E_reduced; the links to the copy_node and original node are stored in \p A, 865 * \p A_reduced, too. 866 */ 867 void make_simple_loopfree( 868 const Graph& G, 869 NodeArray<NodeAttributes>& A, 870 EdgeArray<EdgeAttributes>E, 871 Graph& G_reduced, 872 NodeArray<NodeAttributes>& A_reduced, 873 EdgeArray<EdgeAttributes>& E_reduced); 874 875 //! Deletes parallel edges of \p G_reduced. 876 /** 877 * Saves for each set of parallel edges one representative edge in \p S and 878 * saves in \p new_edgelength the new edge length of this edge in \p G_reduced. 879 */ 880 void delete_parallel_edges( 881 const Graph& G, 882 EdgeArray<EdgeAttributes>& E, 883 Graph& G_reduced, 884 List<edge>& S, 885 EdgeArray<double>& new_edgelength); 886 887 //! Sets for each edge \a e of \a G_reduced in \p S its edgelength to \p new_edgelength[\a e]. 888 /** 889 * Also stores this information in \p E_reduced. 890 */ 891 void update_edgelength( 892 List<edge>& S, 893 EdgeArray <double>& new_edgelength, 894 EdgeArray<EdgeAttributes>& E_reduced); 895 896 //! Returns the value for the strength of the repulsive forces. 897 /** 898 * Used in the postprocessing step; depending on \p n = G.numberOfNodes(). 899 */ get_post_rep_force_strength(int n)900 double get_post_rep_force_strength(int n) { 901 return min(0.2,400.0/double(n)); 902 } 903 904 /** 905 * Adjust positions according to allowedPositions() 906 * 907 * \see FMMMOptions::AllowedPositions 908 */ 909 void adjust_positions(const Graph& G, NodeArray<NodeAttributes>& A); 910 911 //! Creates a simple drawing of \p GA in postscript format and saves it in file \p ps_file. 912 void create_postscript_drawing(GraphAttributes& GA, char* ps_file); 913 914 //! @} 915 //! \name Functions for divide et impera step 916 //! @{ 917 918 //! Constructs the list of connected components of G. 919 /** 920 * Also constructs the corresponding lists with the node / edge attributes 921 * (containing a pointer to the original node in \p G for each node in a subgraph). 922 */ 923 void create_maximum_connected_subGraphs( 924 Graph& G, 925 NodeArray<NodeAttributes>&A, 926 EdgeArray<EdgeAttributes>&E, 927 Graph G_sub[], 928 NodeArray<NodeAttributes> A_sub[], 929 EdgeArray<EdgeAttributes> E_sub[], 930 NodeArray<int>& component); 931 932 //! The drawings of the subgraphs are packed. 933 /** 934 * This is done such that the subgraphs do not overlap and fit into a small 935 * box with the desired aspect ratio. 936 */ 937 void pack_subGraph_drawings( 938 NodeArray<NodeAttributes>& A, 939 Graph G_sub[], 940 NodeArray<NodeAttributes> A_sub[]); 941 942 //! The bounding rectangles of all connected componenents of \a G are calculated and stored in \p R. 943 void calculate_bounding_rectangles_of_components( 944 List<Rectangle>& R, 945 Graph G_sub[], 946 NodeArray<NodeAttributes> A_sub[]); 947 948 //! The bounding rectangle of the componenet_index-th. component of G is returned. 949 Rectangle calculate_bounding_rectangle( 950 Graph& G, 951 NodeArray<NodeAttributes>& A, 952 int componenet_index); 953 954 /** 955 * If number_of_components > 1, the subgraphs \p G_sub are rotated and skipped to 956 * find bounding rectangles with minimum area. The information is saved in \p R and 957 * the node positions in \p A_sub are updated. If number_of_components == 1 a rotation 958 * with minimal aspect ratio is found instead. 959 */ 960 void rotate_components_and_calculate_bounding_rectangles( 961 List<Rectangle>&R, 962 Graph G_sub[], 963 NodeArray<NodeAttributes> A_sub[]); 964 965 /** 966 * Returns the area (aspect ratio area) of a rectangle with width w and height h 967 * if comp_nr > 1 ( comp_nr == 1). 968 */ calculate_area(double width,double height,int comp_nr)969 double calculate_area(double width, double height, int comp_nr) { 970 double scaling = 1.0; 971 if (comp_nr == 1) { //calculate aspect ratio area of the rectangle 972 OGDF_ASSERT( height != 0.0 ); 973 double ratio = width / height; 974 if (ratio < pageRatio()) { //scale width 975 OGDF_ASSERT( ratio != 0.0 ); 976 scaling = pageRatio() / ratio; 977 } else { //scale height 978 OGDF_ASSERT( pageRatio() != 0.0 ); 979 scaling = ratio / pageRatio(); 980 } 981 } 982 return width * height * scaling; 983 } 984 985 /** 986 * The positions of the nodes in the subgraphs are calculated by using the 987 * information stored in R and are exported to A. (The coordinates of components 988 * which surrounding rectangles have been tipped over in the packing step are 989 * tipped over here,too) 990 */ 991 void export_node_positions( 992 NodeArray<NodeAttributes>& A, 993 List<Rectangle>& R, 994 Graph G_sub[], 995 NodeArray<NodeAttributes> A_sub[]); 996 997 //! Frees dynamically allocated memory for the connected component subgraphs. delete_all_subGraphs(Graph G_sub[],NodeArray<NodeAttributes> A_sub[],EdgeArray<EdgeAttributes> E_sub[])998 void delete_all_subGraphs( 999 Graph G_sub[], 1000 NodeArray<NodeAttributes> A_sub[], 1001 EdgeArray<EdgeAttributes> E_sub[]) 1002 { 1003 delete[] G_sub; 1004 delete[] A_sub; 1005 delete[] E_sub; 1006 } 1007 1008 //! @} 1009 //! \name Functions for multilevel step 1010 //! @{ 1011 1012 /** 1013 * Returns the maximum number of iterations for the force calc. step depending 1014 * on act_level, max_level, FixedIterations, MaxIterChange, MaxIterFactor, 1015 * and the number of nodes of the Graph in the actual mutilevel. 1016 */ 1017 int get_max_mult_iter(int act_level, int max_level, int node_nr); 1018 1019 //! @} 1020 //! \name Functions for force calculation 1021 //! @{ 1022 1023 //! The forces are calculated here. 1024 void calculate_forces( 1025 Graph& G, 1026 NodeArray<NodeAttributes>& A, 1027 EdgeArray<EdgeAttributes>& E,NodeArray<DPoint>& F, 1028 NodeArray<DPoint>& F_attr, 1029 NodeArray<DPoint>& F_rep, 1030 NodeArray<DPoint>& last_node_movement, 1031 int iter, 1032 int fine_tuning_step); 1033 1034 //! The length of the computational box in the first iteration is set (down left corner is at (0,0). 1035 void init_boxlength_and_cornercoordinate(Graph& G,NodeArray<NodeAttributes>& A); 1036 1037 //! The initial placements of the nodes are created by using initialPlacementForces(). 1038 void create_initial_placement (Graph& G,NodeArray<NodeAttributes>& A); 1039 1040 //! Places nodes uniformly in a grid. 1041 void create_initial_placement_uniform_grid(const Graph& G, NodeArray<NodeAttributes>& A); 1042 1043 //! Places nodes randomly. 1044 void create_initial_placement_random(const Graph& G, NodeArray<NodeAttributes>& A); 1045 1046 //! Sets all entries of \p F to (0,0). 1047 void init_F (Graph& G, NodeArray<DPoint>& F); 1048 1049 1050 //! Make initializations for the data structures that are used in the choosen class for rep. force calculation. 1051 void make_initialisations_for_rep_calc_classes( 1052 Graph& G/*, 1053 NodeArray<NodeAttributes> &A, 1054 NodeArray<DPoint>& F_rep*/); 1055 1056 //! Calculates repulsive forces for each node. calculate_repulsive_forces(Graph & G,NodeArray<NodeAttributes> & A,NodeArray<DPoint> & F_rep)1057 void calculate_repulsive_forces( 1058 Graph &G, 1059 NodeArray<NodeAttributes>& A, 1060 NodeArray<DPoint>& F_rep) 1061 { 1062 switch (repulsiveForcesCalculation()) { 1063 case FMMMOptions::RepulsiveForcesMethod::Exact: 1064 FR.calculate_exact_repulsive_forces(G,A,F_rep); 1065 break; 1066 case FMMMOptions::RepulsiveForcesMethod::GridApproximation: 1067 FR.calculate_approx_repulsive_forces(G,A,F_rep); 1068 break; 1069 case FMMMOptions::RepulsiveForcesMethod::NMM: 1070 NM.calculate_repulsive_forces(G,A,F_rep); 1071 break; 1072 } 1073 } 1074 1075 1076 //! Deallocates dynamically allocated memory of the choosen rep. calculation class. deallocate_memory_for_rep_calc_classes()1077 void deallocate_memory_for_rep_calc_classes() 1078 { 1079 if(repulsiveForcesCalculation() == FMMMOptions::RepulsiveForcesMethod::NMM) 1080 NM.deallocate_memory(); 1081 } 1082 1083 //! Calculates attractive forces for each node. 1084 void calculate_attractive_forces( 1085 Graph& G, 1086 NodeArray<NodeAttributes> & A, 1087 EdgeArray<EdgeAttributes>& E, 1088 NodeArray<DPoint>& F_attr); 1089 1090 //! Returns the attractive force scalar. 1091 double f_attr_scalar (double d,double ind_ideal_edge_length); 1092 1093 //! Add attractive and repulsive forces for each node. 1094 void add_attr_rep_forces( 1095 Graph& G, 1096 NodeArray<DPoint>& F_attr, 1097 NodeArray<DPoint>& F_rep, 1098 NodeArray<DPoint>& F, 1099 int iter, 1100 int fine_tuning_step); 1101 1102 //! Move the nodes. 1103 void move_nodes(Graph& G,NodeArray<NodeAttributes>& A,NodeArray<DPoint>& F); 1104 1105 //! Computes a new tight computational square-box. 1106 /** 1107 * (Guaranteeing, that all midpoints are inside the square.) 1108 */ 1109 void update_boxlength_and_cornercoordinate(Graph& G,NodeArray<NodeAttributes>& A); 1110 1111 //! Describes the max. radius of a move in one time step, depending on the number of iterations. max_radius(int iter)1112 double max_radius(int iter) { 1113 return (iter == 1) ? boxlength/1000 : boxlength/5; 1114 } 1115 1116 //! The average_ideal_edgelength for all edges is computed. 1117 void set_average_ideal_edgelength(Graph& G,EdgeArray<EdgeAttributes>& E); 1118 1119 /** 1120 * Calculates the average force on each node in the actual iteration, which is 1121 * needed if StopCriterion is scThreshold() or scFixedIterationsOrThreshold(). 1122 */ 1123 double get_average_forcevector_length (Graph& G, NodeArray<DPoint>& F); 1124 1125 /** 1126 * Depending on the direction of \p last_node_movement[\a v], the length of the next 1127 * displacement of node \a v is restricted. 1128 */ 1129 void prevent_oscillations( 1130 Graph& G, 1131 NodeArray<DPoint>& F, 1132 NodeArray<DPoint>& 1133 last_node_movement, 1134 int iter); 1135 1136 //! \p last_node_movement is initialized to \p F (used after first iteration). 1137 void init_last_node_movement( 1138 Graph& G, 1139 NodeArray<DPoint>& F, 1140 NodeArray<DPoint>& last_node_movement); 1141 1142 /** 1143 * If resizeDrawing is true, the drawing is adapted to the ideal average 1144 * edge length by shrinking respectively expanding the drawing area. 1145 */ 1146 void adapt_drawing_to_ideal_average_edgelength( 1147 Graph& G, 1148 NodeArray<NodeAttributes>& A, 1149 EdgeArray<EdgeAttributes>& E); 1150 1151 /** 1152 * The force is restricted to have values within the comp. box (needed for 1153 * exception handling, if the force is too large for further calculations). 1154 */ restrict_force_to_comp_box(DPoint & force)1155 void restrict_force_to_comp_box(DPoint& force) { 1156 double x_min = down_left_corner.m_x; 1157 double x_max = down_left_corner.m_x+boxlength; 1158 double y_min = down_left_corner.m_y; 1159 double y_max = down_left_corner.m_y+boxlength; 1160 if (force.m_x < x_min ) 1161 force.m_x = x_min; 1162 else if (force.m_x > x_max ) 1163 force.m_x = x_max; 1164 if (force.m_y < y_min ) 1165 force.m_y = y_min; 1166 else if (force.m_y > y_max ) 1167 force.m_y = y_max; 1168 } 1169 1170 //! @} 1171 //! \name Functions for analytic information 1172 //! @{ 1173 1174 //! Sets time_total to zero. init_time()1175 void init_time() { time_total = 0; } 1176 1177 //! @} 1178 }; 1179 1180 } 1181